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