docs: update application architecture and database patterns for request-level caching best practices
This commit is contained in:
parent
5e8d11f732
commit
a661ad796c
3 changed files with 68 additions and 5 deletions
|
|
@ -283,14 +283,22 @@ ### **Polymorphic Relationships**
|
|||
|
||||
### **Team-Based Soft Scoping**
|
||||
|
||||
All major resources include team-based query scoping:
|
||||
All major resources include team-based query scoping with request-level caching:
|
||||
|
||||
```php
|
||||
// Automatic team filtering
|
||||
$applications = Application::ownedByCurrentTeam()->get();
|
||||
$servers = Server::ownedByCurrentTeam()->get();
|
||||
// ✅ CORRECT - Use cached methods (request-level cache via once())
|
||||
$applications = Application::ownedByCurrentTeamCached();
|
||||
$servers = Server::ownedByCurrentTeamCached();
|
||||
|
||||
// ✅ CORRECT - Filter cached collection in memory
|
||||
$activeServers = Server::ownedByCurrentTeamCached()->where('is_active', true);
|
||||
|
||||
// Only use query builder when you need eager loading or fresh data
|
||||
$projects = Project::ownedByCurrentTeam()->with('environments')->get();
|
||||
```
|
||||
|
||||
See [Database Patterns](.ai/patterns/database-patterns.md#request-level-caching-with-ownedbycurrentteamcached) for full documentation.
|
||||
|
||||
### **Configuration Inheritance**
|
||||
|
||||
Environment variables cascade from:
|
||||
|
|
|
|||
|
|
@ -243,6 +243,59 @@ ### Database Indexes
|
|||
- **Composite indexes** for common queries
|
||||
- **Unique constraints** for business rules
|
||||
|
||||
### Request-Level Caching with ownedByCurrentTeamCached()
|
||||
|
||||
Many models have both `ownedByCurrentTeam()` (returns query builder) and `ownedByCurrentTeamCached()` (returns cached collection). **Always prefer the cached version** to avoid duplicate database queries within the same request.
|
||||
|
||||
**Models with cached methods available:**
|
||||
- `Server`, `PrivateKey`, `Project`
|
||||
- `Application`
|
||||
- `StandalonePostgresql`, `StandaloneMysql`, `StandaloneRedis`, `StandaloneMariadb`, `StandaloneMongodb`, `StandaloneKeydb`, `StandaloneDragonfly`, `StandaloneClickhouse`
|
||||
- `Service`, `ServiceApplication`, `ServiceDatabase`
|
||||
|
||||
**Usage patterns:**
|
||||
```php
|
||||
// ✅ CORRECT - Uses request-level cache (via Laravel's once() helper)
|
||||
$servers = Server::ownedByCurrentTeamCached();
|
||||
|
||||
// ❌ AVOID - Makes a new database query each time
|
||||
$servers = Server::ownedByCurrentTeam()->get();
|
||||
|
||||
// ✅ CORRECT - Filter cached collection in memory
|
||||
$activeServers = Server::ownedByCurrentTeamCached()->where('is_active', true);
|
||||
$server = Server::ownedByCurrentTeamCached()->firstWhere('id', $serverId);
|
||||
$serverIds = Server::ownedByCurrentTeamCached()->pluck('id');
|
||||
|
||||
// ❌ AVOID - Making filtered database queries when data is already cached
|
||||
$activeServers = Server::ownedByCurrentTeam()->where('is_active', true)->get();
|
||||
```
|
||||
|
||||
**When to use which:**
|
||||
- `ownedByCurrentTeamCached()` - **Default choice** for reading team data
|
||||
- `ownedByCurrentTeam()` - Only when you need to chain query builder methods that can't be done on collections (like `with()` for eager loading), or when you explicitly need a fresh database query
|
||||
|
||||
**Implementation pattern for new models:**
|
||||
```php
|
||||
/**
|
||||
* Get query builder for resources owned by current team.
|
||||
* If you need all resources without further query chaining, use ownedByCurrentTeamCached() instead.
|
||||
*/
|
||||
public static function ownedByCurrentTeam()
|
||||
{
|
||||
return self::whereTeamId(currentTeam()->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all resources owned by current team (cached for request duration).
|
||||
*/
|
||||
public static function ownedByCurrentTeamCached()
|
||||
{
|
||||
return once(function () {
|
||||
return self::ownedByCurrentTeam()->get();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Data Consistency Patterns
|
||||
|
||||
### Database Transactions
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ ### Performance Considerations
|
|||
- Queue heavy operations
|
||||
- Optimize database queries with proper indexes
|
||||
- Use chunking for large data operations
|
||||
- **CRITICAL**: Use `ownedByCurrentTeamCached()` instead of `ownedByCurrentTeam()->get()`
|
||||
|
||||
### Code Style
|
||||
- Follow PSR-12 coding standards
|
||||
|
|
@ -318,3 +319,4 @@ ### Livewire & Frontend
|
|||
|
||||
Random other things you should remember:
|
||||
- App\Models\Application::team must return a relationship instance., always use team()
|
||||
- Always use `Model::ownedByCurrentTeamCached()` instead of `Model::ownedByCurrentTeam()->get()` for team-scoped queries to avoid duplicate database queries
|
||||
Loading…
Reference in a new issue