Start with feature ownership

A feature folder should contain the UI, routes, state, and feature-specific services needed to understand that slice of the product. Shared code should be earned, not guessed upfront.

The first architecture mistake is making everything shared before you know what is actually common.

ts
src/app/
  features/
    billing/
      pages/
      components/
      billing-api.service.ts
      billing.store.ts
    users/
      pages/
      components/
      users-api.service.ts

Smart and presentational is still useful

The labels are imperfect, but the boundary is helpful. Components that fetch, coordinate, or own workflow state should not also become large template files full of repeated UI details.

Presentational components should receive data and callbacks. They should be easy to test and easy to move.

Try the idea

Folder structure explorerfeature
src/app/feature/pages/src/app/feature/components/src/app/feature/state/src/app/feature/feature-api.service.ts

Keep an API layer

Do not scatter raw HTTP calls across components. An API service gives you one place to map backend response shapes, handle typed parameters, and make failures predictable.

Production notes for Angular apps

Angular features stay maintainable when state ownership is obvious. Before adding another shared service or utility, decide whether the behavior belongs to a component, a feature boundary, an API service, or a reusable UI primitive.

The best Angular code is boring to navigate: feature folders are predictable, templates stay readable, and async behavior has a clear home instead of being scattered through lifecycle hooks.

Conclusion

Good Angular architecture is less about clever folders and more about keeping product boundaries visible as the app grows.