Skillshub angular-architecture

install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/Gentleman-Programming/Gentleman-Skills/architecture" ~/.claude/skills/comeonoliver-skillshub-angular-architecture && rm -rf "$T"
manifest: skills/Gentleman-Programming/Gentleman-Skills/architecture/SKILL.md
source content

The Scope Rule (REQUIRED)

"Scope determines structure" - Where a component lives depends on its usage.

UsagePlacement
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 injection
  • class
    and
    style
    bindings over
    ngClass
    /
    ngStyle
  • protected
    for template-only members
  • readonly
    for 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 SaysWe DoWhy
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