myCRM/.claude/ARCHITECTURE.md
olli 8a132d2fb9 feat: Implement ProjectTask module with full CRUD functionality
- Added ProjectTask entity with fields for name, description, budget, hour contingent, hourly rate, and total price.
- Created ProjectTaskRepository with methods for querying tasks by project and user access.
- Implemented ProjectTaskVoter for fine-grained access control based on user roles and project membership.
- Developed ProjectTaskSecurityListener to enforce permission checks during task creation.
- Introduced custom ProjectTaskProjectFilter for filtering tasks based on project existence.
- Integrated ProjectTask management in the frontend with Vue.js components, including CRUD operations and filtering capabilities.
- Added API endpoints for ProjectTask with appropriate security measures.
- Created migration for project_tasks table in the database.
- Updated documentation to reflect new module features and usage.
2025-11-14 17:12:40 +01:00

269 lines
7.8 KiB
Markdown

# myCRM Architecture Overview
## Quick Reference for Claude
### Security Architecture
This codebase uses a **multi-layered security system** combining:
1. **Symfony Authentication** - User login, password hashing via bcrypt
2. **Role-Based Access Control (RBAC)** - Users → Roles → Modules → Permissions
3. **Custom Voters** - Fine-grained entity-level authorization
4. **API Platform** - Per-operation security expressions
5. **Query Extensions** - Automatic filtering of accessible data
See `/SECURITY_ARCHITECTURE.md` for comprehensive details.
### Entity Relationships - Quick Diagram
```
User
├── Standard Roles: ROLE_ADMIN, ROLE_USER (in 'roles' JSON column)
├── Application Roles: Collection<Role> (ManyToMany)
│ └── Role
│ └── Permissions: Collection<RolePermission> (OneToMany)
│ └── RolePermission
│ └── Module (the module being granted permission for)
└── Can belong to Project teams: Collection<Project> (ManyToMany)
Project
├── owner: User (REQUIRED)
├── teamMembers: Collection<User> (ManyToMany)
├── customer: Contact
├── status: ProjectStatus
└── gitRepositories: Collection<GitRepository> (OneToMany)
ProjectTask
├── project: Project (nullable - can be project-independent)
└── Budget & hourly tracking
GitRepository
├── project: Project (REQUIRED)
└── URL, branch, provider info
Contact
├── contactPersons: Collection<ContactPerson> (OneToMany)
└── Company info: name, address, tax numbers, etc.
ContactPerson
└── contact: Contact (ManyToOne - no separate permissions)
```
### Permission Hierarchy
**Level 1: Symfony Standard Roles**
- Checked in `config/packages/security.yaml` access_control
- Used for basic authentication gates (API requires `IS_AUTHENTICATED_FULLY`)
**Level 2: Module-Based Permissions**
- `User.hasModulePermission(moduleCode, action)` checks:
- User's application roles
- Each role's RolePermission for the module
- The specific action flag (canView, canCreate, canEdit, etc.)
**Level 3: Object-Level Voters**
- `ModuleVoter` - Module-level permissions (string subject or ModuleAwareInterface)
- `ProjectVoter` - Ownership/team access to projects
- `ProjectTaskVoter` - Project-based + admin-only for standalone tasks
- `GitRepositoryVoter` - Project-based access
**Level 4: Event Listeners**
- `ProjectTaskSecurityListener` - Additional prePersist check
### Core Files to Know
**Security Components:**
- `src/Security/Voter/ModuleVoter.php` - Routes to `user.hasModulePermission()`
- `src/Security/Voter/ProjectVoter.php` - Checks `project.owner === user` or team
- `src/Security/Voter/ProjectTaskVoter.php` - Combines project + admin checks
- `src/Security/Voter/GitRepositoryVoter.php` - Tied to project access
**Entities:**
- `src/Entity/User.php` - hasModulePermission() method
- `src/Entity/Role.php` - permissions collection
- `src/Entity/RolePermission.php` - defines per-module flags
- `src/Entity/Module.php` - registry of modules
- `src/Entity/Project.php` - hasAccess() checks owner/team
- `src/Entity/Interface/ModuleAwareInterface.php` - getModuleName()
**API Configuration:**
- `config/packages/api_platform.yaml` - Global API defaults
- `config/packages/security.yaml` - Firewall, access_control
- Entity `#[ApiResource]` attributes - Per-operation security expressions
### API Filters
Most entities have API filters:
- `SearchFilter` - Partial text search
- `BooleanFilter` - Filter by boolean fields
- `DateFilter` - Filter by date ranges
- Custom `ProjectTaskProjectFilter` - hasProject filter for tasks
### Authentication Methods
1. **Form Login** - `LoginFormAuthenticator` - Email + password form
2. **OAuth** - `PocketIdAuthenticator` - OIDC provider integration
Both update `lastLoginAt` in LoginSuccessListener.
### Data Serialization
All APIs use serializer groups to control what's returned:
- `{entity}:read` - Fields returned in GET
- `{entity}:write` - Fields accepted in POST/PUT
Example: User with `#[Groups(['user:read', 'project:read'])]` appears in both user and project responses.
### Key Patterns
**Module-Based Permission Check:**
```php
is_granted('VIEW', 'contacts') // Collection operation
ModuleVoter.supports() true
ModuleVoter.voteOnAttribute('VIEW', 'contacts', $token)
user.hasModulePermission('contacts', 'view')
```
**Object-Level Access Check:**
```php
is_granted('DELETE', $project) // Delete operation
ProjectVoter.supports() true
ProjectVoter.voteOnAttribute('DELETE', $project, $token)
project.getOwner() === $user
```
**Project-Related Filtering:**
```
ProjectAccessExtension applies to Project GetCollection
Adds: WHERE owner = :user OR teamMembers = :user
User sees only their projects
```
### Adding New Features
**New Module-Based Entity:**
1. Implement `ModuleAwareInterface::getModuleName()`
2. Create `Module` record in database
3. Add API security: `new GetCollection(security: "is_granted('VIEW', 'module_code')")`
4. Create RolePermissions for existing roles
**New Project-Related Entity:**
1. Add `project: Project` relationship
2. Create custom Voter like `ProjectTaskVoter`
3. Use in API: `new Get(security: "is_granted('VIEW', object)")`
**New User Role:**
1. Create `Role` entity
2. Add `RolePermission` records for each module
3. Assign to users via `user.addUserRole(role)`
### Common Security Attributes
Used in voters and API operations:
- `VIEW` - Can read/list
- `CREATE` - Can create new
- `EDIT` - Can update
- `DELETE` - Can remove
- `EXPORT` - Can export data
- `MANAGE` - Admin functions
### Important Constants
**Voter Attributes:**
```php
ProjectVoter::VIEW
ProjectVoter::EDIT
ProjectVoter::DELETE
ProjectVoter::CREATE
// Similar for other voters
```
**API Platform Groups:**
```
{entity}:read → Normalization (GET)
{entity}:write → Denormalization (POST/PUT)
```
**Symfony Standard Roles:**
```
ROLE_USER → Authenticated user
ROLE_ADMIN → All permissions (bypasses voters)
```
---
## Quick Debugging Checklist
1. **User can't access API endpoint?**
- Check `access_control` in security.yaml
- Check API operation security expression
- Check voter implementation
2. **User has role but can't perform action?**
- Verify RolePermission exists for that role+module
- Check the specific permission flag (canView, etc.)
- Verify module code matches (case-sensitive!)
3. **Non-admin accessing admin resource?**
- Check ROLE_ADMIN bypass in voter
- Verify voter supports() returns true
- Look at voteOnAttribute() logic
4. **Permission check in code?**
```php
// Get current user
$user = $this->getUser(); // null if not authenticated
// Check module permission
if ($user->hasModulePermission('contacts', 'create')) {
// Allow
}
// In Twig
{% if app.user.hasModulePermission('contacts', 'view') %}...{% endif %}
// In security expressions
is_granted('CREATE', 'contacts')
is_granted('EDIT', $contact)
```
---
## Files Changed Recently
Check git status to see security-related changes:
- `src/Security/Voter/*.php` - Voter implementations
- `src/Entity/*.php` - Entity definitions
- `src/EventListener/*.php` - Security listeners
- `config/packages/security.yaml` - Auth configuration
---
## Testing Security
**Unit Testing:**
- Create user and project fixtures
- Test voter returns ALLOW/DENY/ABSTAIN correctly
- Test edge cases (null owner, empty team, etc.)
**Integration Testing:**
- Make API calls as different users
- Verify 403 Forbidden for unauthorized access
- Verify 200 OK for authorized access
- Check returned data respects serializer groups
---
## See Also
- `/SECURITY_ARCHITECTURE.md` - Complete security documentation
- `/docs/PERMISSIONS.md` - User management and permissions guide
- `config/packages/security.yaml` - Security configuration
- API Platform docs: https://api-platform.com/docs/core/security/