The Scope Rule (REQUIRED)
"Scope determines structure" - Where a component lives depends on its usage.
| Usage | Placement |
|---|---|
| Used by 1 feature | features/[feature]/components/ |
| Used by 2+ features | features/shared/components/ |
Example
features/
shopping-cart/
shopping-cart.ts # Main component = feature name
components/
cart-item.ts # Used ONLY by shopping-cart
cart-summary.ts # Used ONLY by shopping-cart
checkout/
checkout.ts
components/
payment-form.ts # Used ONLY by checkout
shared/
components/
button.ts # Used by shopping-cart AND checkout
modal.ts # Used by multiple features
Project Structure
src/app/
features/
[feature-name]/
[feature-name].ts # Main component (same name as folder)
components/ # Feature-specific components
services/ # Feature-specific services
models/ # Feature-specific types
shared/ # ONLY for 2+ feature usage
components/
services/
pipes/
core/ # App-wide singletons
services/
interceptors/
guards/
app.ts
app.config.ts
routes.ts
main.ts
File Naming (REQUIRED)
No .component, .service, .model suffixes. The folder tells you what it is.
✅ user-profile.ts
❌ user-profile.component.ts
✅ cart.ts
❌ cart.service.ts
✅ user.ts
❌ user.model.ts
Style Guide
What We Follow (from official docs)
inject()over constructor injectionclassandstylebindings overngClass/ngStyleprotectedfor template-only membersreadonlyfor inputs, outputs, queries- Name handlers for action (
saveUser) not event (handleClick) - Keep lifecycle hooks simple - delegate to well-named methods
- One concept per file
@Component({...})
export class UserProfileComponent {
// 1. Injected dependencies
private readonly userService = inject(UserService);
// 2. Inputs/Outputs
readonly userId = input.required<string>();
readonly userSaved = output<User>();
// 3. Internal state
private readonly _loading = signal(false);
readonly loading = this._loading.asReadonly();
// 4. Computed
protected readonly displayName = computed(() => ...);
// 5. Methods
save(): void { ... }
}
What We Override
| Official Says | We Do | Why |
|---|---|---|
user-profile.component.ts |
user-profile.ts |
Redundant - folder tells context |
user.service.ts |
user.ts |
Same |
Commands
# New project
ng new my-app --style=scss --ssr=false
# Component in feature
ng g c features/products/components/product-card --flat
# Service in feature
ng g s features/products/services/product --flat
# Guard in core
ng g g core/guards/auth --functional
Resources
🎯 Selective Reading Rule
Read ONLY files relevant to the request! Check the content map, find what you need.
| File | Description | When to Read |
|---|---|---|
context-discovery.md |
Questions to ask, project classification | Starting architecture design |
trade-off-analysis.md |
ADR templates, trade-off framework | Documenting decisions |
pattern-selection.md |
Decision trees, anti-patterns | Choosing patterns |
examples.md |
MVP, SaaS, Enterprise examples | Reference implementations |
patterns-reference.md |
Quick lookup for patterns | Pattern comparison |
🔗 Related Skills
| Skill | Use For |
|---|---|
@[skills/database-design] |
Database schema design |
@[skills/api-patterns] |
API design patterns |
@[skills/deployment-procedures] |
Deployment architecture |
Core Principle
"Simplicity is the ultimate sophistication."
- Start simple
- Add complexity ONLY when proven necessary
- You can always add patterns later
- Removing complexity is MUCH harder than adding it
Validation Checklist
Before finalizing architecture:
- Requirements clearly understood
- Constraints identified
- Each decision has trade-off analysis
- Simpler alternatives considered
- ADRs written for significant decisions
- Team expertise matches chosen patterns
When to Use
This skill is applicable to execute the workflow or actions described in the overview.