Skip to content

Commit 62924ee

Browse files
committed
feat: initialize demo project with feature-based architecture
1 parent 1350f2b commit 62924ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+1160
-63
lines changed

README.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,150 @@
2828

2929
---
3030

31+
## 📁 Project Structure Overview
32+
33+
This Angular project is structured using feature-based architecture and fully adopts the standalone component API, promoting modularity, reusability, and scalability.
34+
35+
#### Key Highlights
36+
37+
`Standalone Components`: All components and routes are declared with standalone: true, eliminating the need for NgModules.
38+
39+
`Feature-Based Organization`: Each domain (e.g., auth, post, user) is self-contained, including APIs, models, pages, services, and routing.
40+
41+
`Separation of Concerns`: Shared utilities, guards, interceptors, and services are centralized in core/ and shared/.
42+
43+
`Layout-Driven Routing`: Layouts (e.g., auth-layout, home-layout) structure route groups with their own UI shells.
44+
45+
#### Folder Overview
46+
47+
`app/`: Root configuration and bootstrap files.
48+
49+
`core/`: Application-wide logic – guards, interceptors, constants, services, and utilities.
50+
51+
`features/`: Modular, domain-specific features with full encapsulation of UI, logic, and routing.
52+
53+
`layouts/`: Defines structural layouts with associated routes.
54+
55+
`shared/`: Reusable UI components, directives, pipes, and design utilities.
56+
57+
`styles/`: Global styles and SCSS utilities.
58+
59+
`environments/`: Standard Angular environment configuration.
60+
61+
```bash
62+
src
63+
├── app
64+
│ ├── app.component.ts
65+
│ ├── app.config.ts
66+
│ ├── app.routes.ts
67+
│ ├── core
68+
│ │ ├── constants
69+
│ │ │ ├── api-service.constant.ts
70+
│ │ │ └── index.ts
71+
│ │ ├── guards
72+
│ │ │ ├── auth.guard.ts
73+
│ │ │ ├── index.ts
74+
│ │ │ ├── integer-param.guard.ts
75+
│ │ │ ├── no-auth.guard.ts
76+
│ │ │ └── role.guard.ts
77+
│ │ ├── interceptors
78+
│ │ │ ├── error.interceptor.ts
79+
│ │ │ ├── index.ts
80+
│ │ │ ├── logger.interceptor.ts
81+
│ │ │ └── switch-service.interceptor.ts
82+
│ │ ├── models
83+
│ │ │ ├── index.ts
84+
│ │ │ └── session.model.ts
85+
│ │ ├── services
86+
│ │ │ ├── index.ts
87+
│ │ │ └── session.service.ts
88+
│ │ └── utils
89+
│ │ ├── fetch-state
90+
│ │ │ ├── fetch-state.type.ts
91+
│ │ │ └── to-fetch-state.operator.ts
92+
│ │ └── index.ts
93+
│ ├── features
94+
│ │ ├── auth
95+
│ │ │ ├── apis
96+
│ │ │ │ └── index.ts
97+
│ │ │ ├── auth.routes.ts
98+
│ │ │ ├── components
99+
│ │ │ │ └── index.ts
100+
│ │ │ ├── models
101+
│ │ │ │ └── index.ts
102+
│ │ │ ├── pages
103+
│ │ │ │ ├── login.component.ts
104+
│ │ │ │ └── register.component.ts
105+
│ │ │ └── services
106+
│ │ │ └── index.ts
107+
│ │ ├── post
108+
│ │ │ ├── apis
109+
│ │ │ │ ├── index.ts
110+
│ │ │ │ └── post.api.ts
111+
│ │ │ ├── components
112+
│ │ │ │ ├── index.ts
113+
│ │ │ │ └── post.component.ts
114+
│ │ │ ├── models
115+
│ │ │ │ ├── index.ts
116+
│ │ │ │ └── post.model.ts
117+
│ │ │ ├── pages
118+
│ │ │ │ ├── post-detail.component.ts
119+
│ │ │ │ └── post-listing.component.ts
120+
│ │ │ ├── post.routes.ts
121+
│ │ │ └── services
122+
│ │ │ ├── index.ts
123+
│ │ │ └── post.service.ts
124+
│ │ └── user
125+
│ │ ├── apis
126+
│ │ │ ├── index.ts
127+
│ │ │ └── user.api.ts
128+
│ │ ├── components
129+
│ │ │ ├── index.ts
130+
│ │ │ └── user.component.ts
131+
│ │ ├── models
132+
│ │ │ ├── index.ts
133+
│ │ │ └── user.model.ts
134+
│ │ ├── pages
135+
│ │ │ ├── user-detail.component.ts
136+
│ │ │ └── user-listing.component.ts
137+
│ │ ├── services
138+
│ │ │ ├── index.ts
139+
│ │ │ └── user.service.ts
140+
│ │ └── user.routes.ts
141+
│ ├── layouts
142+
│ │ ├── auth-layout
143+
│ │ │ ├── auth-layout.component.ts
144+
│ │ │ └── auth-layout.routes.ts
145+
│ │ ├── forbidden-page.component.ts
146+
│ │ ├── home-layout
147+
│ │ │ ├── home-layout.component.ts
148+
│ │ │ └── home-layout.routes.ts
149+
│ │ ├── maintenance-page.component.ts
150+
│ │ └── not-found-page.component.ts
151+
│ └── shared
152+
│ ├── components
153+
│ │ └── index.ts
154+
│ ├── directives
155+
│ │ └── index.ts
156+
│ ├── icons
157+
│ │ └── icon.module.ts
158+
│ ├── pipes
159+
│ │ └── index.ts
160+
│ └── ui
161+
│ └── index.ts
162+
├── environments
163+
│ ├── environment.prod.ts
164+
│ └── environment.ts
165+
├── index.html
166+
├── main.ts
167+
├── styles
168+
│ ├── _font.scss
169+
│ └── _utils.scss
170+
└── styles.scss
171+
```
172+
173+
---
174+
31175
## 🛠️ Setup Instructions
32176

33177
1. Clone the repository:

src/app/app.component.html

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/app/app.component.scss

Whitespace-only changes.

src/app/app.component.spec.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/app/app.component.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { ChangeDetectionStrategy, Component } from "@angular/core";
1+
import { Component } from "@angular/core";
22
import { RouterOutlet } from "@angular/router";
3-
import { IconModule } from "./shared/icon.module";
43

54
@Component({
65
selector: "app-root",
7-
imports: [RouterOutlet, IconModule],
8-
templateUrl: "./app.component.html",
9-
styleUrl: "./app.component.scss",
10-
changeDetection: ChangeDetectionStrategy.OnPush,
6+
imports: [RouterOutlet],
117
standalone: true,
8+
template: `
9+
<div class="!max-w-[1200px] mx-auto">
10+
<router-outlet></router-outlet>
11+
</div>
12+
`,
1213
})
1314
export class AppComponent {}

src/app/app.config.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1+
import { provideHttpClient, withInterceptors } from "@angular/common/http";
12
import { ApplicationConfig, provideExperimentalZonelessChangeDetection } from "@angular/core";
2-
import {
3-
PreloadAllModules,
4-
provideRouter,
5-
withPreloading,
6-
withViewTransitions,
7-
} from "@angular/router";
8-
3+
import { provideRouter, withComponentInputBinding, withViewTransitions } from "@angular/router";
4+
import { errorInterceptor, loggerInterceptor, switchServiceInterceptor } from "@core/interceptors";
95
import { routes } from "./app.routes";
106

117
export const appConfig: ApplicationConfig = {
@@ -14,8 +10,19 @@ export const appConfig: ApplicationConfig = {
1410
provideRouter(
1511
routes,
1612
withViewTransitions(),
17-
withPreloading(PreloadAllModules),
18-
//
13+
withComponentInputBinding(),
14+
// ...
15+
),
16+
provideHttpClient(
17+
withInterceptors(
18+
[
19+
switchServiceInterceptor,
20+
loggerInterceptor,
21+
errorInterceptor,
22+
// ...
23+
],
24+
// ...
25+
),
1926
),
2027
],
2128
};

src/app/app.routes.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
11
import { Routes } from "@angular/router";
2+
import { authGuard } from "@core/guards";
3+
import { noAuthGuard } from "@core/guards/no-auth.guard";
24

3-
export const routes: Routes = [];
5+
export const routes: Routes = [
6+
{
7+
path: "",
8+
pathMatch: "full",
9+
redirectTo: "home",
10+
},
11+
{
12+
path: "home",
13+
canMatch: [authGuard],
14+
loadChildren: () =>
15+
import("./layouts/home-layout/home-layout.routes").then((r) => r.homeLayoutRoutes),
16+
},
17+
{
18+
path: "auth",
19+
canMatch: [noAuthGuard],
20+
loadChildren: () =>
21+
import("./layouts/auth-layout/auth-layout.routes").then((r) => r.authLayoutRoutes),
22+
},
23+
{
24+
path: "maintenance",
25+
loadComponent: () =>
26+
import("./layouts/maintenance-page.component").then((c) => c.MaintenancePageComponent),
27+
},
28+
{
29+
path: "forbidden",
30+
loadComponent: () =>
31+
import("./layouts/forbidden-page.component").then((c) => c.ForbiddenPageComponent),
32+
},
33+
{
34+
path: "**",
35+
loadComponent: () =>
36+
import("./layouts/not-found-page.component").then((c) => c.NotFoundPageComponent),
37+
},
38+
];
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export enum API_SERVICE {
2+
POST = "POST_SERVICE_API",
3+
USER = "USER_SERVICE_API",
4+
}

src/app/core/constants/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { API_SERVICE } from "./api-service.constant";

src/app/core/guards/auth.guard.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { inject } from "@angular/core";
2+
import { CanMatchFn, Router } from "@angular/router";
3+
import { SessionService } from "@core/services";
4+
5+
export const authGuard: CanMatchFn = () => {
6+
const router = inject(Router);
7+
const isValid = SessionService.isLogIn() && !SessionService.isExpiredSession();
8+
9+
if (!isValid) {
10+
return router.parseUrl("/auth/login");
11+
}
12+
13+
return true;
14+
};

0 commit comments

Comments
 (0)