用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Objective-Arts/lens-dist --skill angular-arch命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | angular-arch |
| description | Angular architecture and organization patterns |
| allowed-tools | [] |
Deborah Kurata's core belief: Well-organized code is maintainable code. Architecture decisions made early compound over the life of a project.
"Structure your Angular application so that you can locate code quickly, identify what the code does at a glance, keep the flattest structure possible, and stay DRY."
The LIFT principle:
Organize by feature, not by type.
Not this (organize by type):
src/app/
├── components/
│ ├── user-list.component.ts
│ ├── product-list.component.ts
│ └── order-list.component.ts
├── services/
│ ├── user.service.ts
│ ├── product.service.ts
│ └── order.service.ts
└── models/
├── user.model.ts
├── product.model.ts
└── order.model.ts
This (organize by feature):
src/app/
├── users/
│ ├── user-list.component.ts
│ ├── user-detail.component.ts
│ ├── user.service.ts
│ ├── user.model.ts
│ └── users.module.ts
├── products/
│ ├── product-list.component.ts
│ ├── product.service.ts
│ └── products.module.ts
└── shared/
├── components/
├── pipes/
└── shared.module.ts
Five types of modules:
| Module Type | Purpose | Loads |
|---|---|---|
| Root (App) | Bootstrap | Once at startup |
| Feature | Business feature | Lazy loaded |
| Shared | Reusable components | Imported by features |
| Core | Singleton services | Once in AppModule |
| Routing | Route configuration | With parent module |
// Core module - singleton services, guards
@NgModule({
providers: [AuthService, LoggingService]
})
export class CoreModule {
constructor(@Optional() @SkipSelf() parent: CoreModule) {
if (parent) {
throw new Error('CoreModule already loaded. Import only in AppModule.');
}
}
}
// Shared module - reusable, no singletons
@NgModule({
declarations: [SpinnerComponent, TruncatePipe],
exports: [SpinnerComponent, TruncatePipe, CommonModule]
})
export class SharedModule {}
Clear separation of concerns.
CONTAINER (Smart) PRESENTATIONAL (Dumb)
───────────────── ─────────────────────
user-shell.component user-list.component
user-detail.component
user-form.component
Responsibilities: Responsibilities:
- Fetch data - Display data
- Handle state - Emit events
- Coordinate children - No service injection
- Route handling - Pure @Input/@Output
Naming convention:
feature/
├── feature-shell.component.ts # Smart container
├── feature-list.component.ts # Presentational
├── feature-detail.component.ts # Presentational
├── feature-edit.component.ts # Presentational
└── feature.service.ts
Export public API, hide internals.
// users/index.ts
export * from './users.module';
export * from './user.model';
export * from './user.service';
// Don't export internal components
// Importing from outside the feature:
import { UserService, User } from '@app/users';
Use TypeScript path aliases for clean imports.
tsconfig.json:
{
"compilerOptions": {
"paths": {
"@app/*": ["src/app/*"],
"@core/*": ["src/app/core/*"],
"@shared/*": ["src/app/shared/*"],
"@env/*": ["src/environments/*"]
}
}
}
Usage:
// Instead of: import { UserService } from '../../../core/services/user.service';
import { UserService } from '@core/services/user.service';
Choose complexity appropriate to your app.
COMPLEXITY LEVEL SOLUTION
──────────────── ────────
Simple Services + BehaviorSubject
Medium Component Store (@ngrx/component-store)
Complex Global Store (@ngrx/store)
Simple state (service-based):
@Injectable({ providedIn: 'root' })
export class UserStateService {
private usersSubject = new BehaviorSubject<User[]>([]);
users$ = this.usersSubject.asObservable();
setUsers(users: User[]) {
this.usersSubject.next(users);
}
}
Medium state (component store):
interface UserState {
users: User[];
loading: boolean;
}
@Injectable()
export class UserStore extends ComponentStore<UserState> {
readonly users$ = this.select(state => state.users);
readonly loading$ = this.select(state => state.loading);
readonly loadUsers = this.effect<void>(trigger$ =>
trigger$.pipe(
tap(() => this.patchState({ loading: true })),
switchMap(() => this.userService.getAll().pipe(
tapResponse(
users => this.patchState({ users, loading: false }),
error => .({ : })
)
))
)
);
}
One routing module per feature, lazy loaded.
// app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{
path: 'users',
loadChildren: () => import('./users/users.module').then(m => m.UsersModule)
},
{
path: 'products',
loadChildren: () => import('./products/products.module').then(m => m.ProductsModule)
},
{ path: '**', component: PageNotFoundComponent }
];
// users/users-routing.module.ts
const routes: Routes = [
{
path: '',
component: UserShellComponent,
children: [
{ path: '', component: UserListComponent },
{ path: ':id', : },
{ : , : }
]
}
];
Services should be focused and testable.
// Data service - HTTP operations
@Injectable({ providedIn: 'root' })
export class UserDataService {
private url = '/api/users';
constructor(private http: HttpClient) {}
getAll(): Observable<User[]> {
return this.http.get<User[]>(this.url);
}
getById(id: number): Observable<User> {
return this.http.get<User>(`${this.url}/${id}`);
}
}
// Facade service - coordinates multiple data services
@Injectable({ providedIn: 'root' })
export class UserFacadeService {
constructor(
private userData: UserDataService,
private userState: UserStateService
) {}
() {
..().( {
..(users);
});
}
}
Small, focused interfaces over large ones.
// Not this - one big interface
interface User {
id: number;
name: string;
email: string;
address: Address;
orders: Order[];
preferences: Preferences;
// ... 20 more properties
}
// This - focused interfaces
interface UserBasic {
id: number;
name: string;
email: string;
}
interface UserWithAddress extends UserBasic {
address: Address;
}
interface UserWithOrders extends UserBasic {
orders: Order[];
}
ELEMENT NAMING CONVENTION
─────── ─────────────────
Feature module users.module.ts
Routing module users-routing.module.ts
Component user-list.component.ts
Service user.service.ts
Directive highlight.directive.ts
Pipe truncate.pipe.ts
Guard auth.guard.ts
Resolver user.resolver.ts
Interceptor logging.interceptor.ts
Model/Interface user.model.ts
Before committing architecture decisions, ask:
Apply these checks:
Use a different skill when:
angular-coreangular-perfrxjsdesign-patternsKurata is the Angular organization skill—use it for project structure, module design, and architecture patterns.
"Good architecture is not about choosing the right technology—it's about organizing code so your team can work effectively." — Deborah Kurata