Skip to content

gachlab/conduit-web-angular

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

47 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Conduit Web Angular

A modern Angular implementation of the RealWorld Conduit app with a clean 3-layer architecture.

πŸ—οΈ Architecture Overview

This project implements a framework-agnostic 3-layer architecture that separates concerns and enables code reuse across different frameworks:

Backend API (Single Source of Truth)
    ↓
Core Services (Atomic, Pure TypeScript)
    ↓
Page Services (Orchestrators, Pure TypeScript)
    ↓
Page Components (Adapters, Angular-specific)
    ↓
UI Components (Presentational)

Layer 1: Core Services

  • Pure TypeScript (no Angular dependencies)
  • Atomic API calls (one service per resource)
  • Implement TypeScript interfaces
  • Reusable across React, Vue, Svelte
  • Return Promise<Data>

Layer 2: Page Services

  • Pure TypeScript (framework-agnostic)
  • Orchestrate multiple Core Services
  • Transform and combine data
  • Return Promise<PageState>
  • Export TypeScript types for reuse

Layer 3: Page Components

  • Angular-specific adapters
  • Convert Promise β†’ Signal
  • Manage reactive state
  • Dispatch actions to Page Services
  • Pass data to UI Components

Layer 4: UI Components

  • Presentational components
  • Receive data via @Input()
  • Emit events via @Output()
  • No business logic

πŸš€ Tech Stack

  • Angular 21 - Latest version with standalone components
  • Zoneless Mode - Better performance without Zone.js
  • Signals - Modern reactive state management
  • TypeScript - Full type safety (no any types)
  • Vitest - Fast unit testing (96 tests, 99.38% coverage)
  • ESLint - Code quality and consistency

πŸ“ Project Structure

src/
β”œβ”€β”€ core/                          # Framework-agnostic
β”‚   β”œβ”€β”€ services/                  # Core Services (atomic API calls)
β”‚   β”‚   β”œβ”€β”€ articles-api.service.ts
β”‚   β”‚   β”œβ”€β”€ tags-api.service.ts
β”‚   β”‚   β”œβ”€β”€ user-api.service.ts
β”‚   β”‚   β”œβ”€β”€ profiles-api.service.ts
β”‚   β”‚   β”œβ”€β”€ comments-api.service.ts
β”‚   β”‚   β”œβ”€β”€ mock-api.service.ts    # Mock API for development
β”‚   β”‚   β”œβ”€β”€ api.interfaces.ts      # TypeScript interfaces
β”‚   β”‚   └── retry.util.ts          # Retry logic with exponential backoff
β”‚   β”‚
β”‚   └── page-services/             # Page Services (orchestrators)
β”‚       β”œβ”€β”€ home-page.service.ts
β”‚       β”œβ”€β”€ article-details-page.service.ts
β”‚       β”œβ”€β”€ signin-page.service.ts
β”‚       β”œβ”€β”€ signup-page.service.ts
β”‚       β”œβ”€β”€ settings-page.service.ts
β”‚       β”œβ”€β”€ editor-page.service.ts
β”‚       β”œβ”€β”€ profile-page.service.ts
β”‚       └── page-state.types.ts    # Generic PageState type
β”‚
└── app/                           # Angular-specific
    β”œβ”€β”€ conduit-pages-*/           # Page Components (adapters)
    β”‚   β”œβ”€β”€ component.ts           # Adapter: PageService β†’ Signal
    β”‚   └── template.html          # Orchestrates UI Components
    β”‚
    β”œβ”€β”€ components/                # UI Components (presentational)
    β”‚   └── conduit-*/
    β”‚       β”œβ”€β”€ component.ts       # @Input/@Output only
    β”‚       └── template.html      # Pure presentation
    β”‚
    β”œβ”€β”€ app.component.ts           # Root component
    β”œβ”€β”€ app.routes.ts              # Route configuration
    β”œβ”€β”€ app.service.ts             # App-level state
    └── user.service.ts            # User authentication state

🎯 Key Features

Framework-Agnostic Services

Core and Page Services are Pure TypeScript with no Angular dependencies:

  • βœ… No @Injectable() decorator
  • βœ… No RxJS Observables
  • βœ… No Angular HttpClient
  • βœ… Can be reused in React, Vue, Svelte

Type Safety

  • Zero any types in the codebase
  • Exported TypeScript interfaces for all entities
  • Generic PageState<TData, TExtra> type
  • Full IntelliSense support

Mock API

  • Complete mock implementation for development
  • No backend required
  • Configurable latency simulation
  • localStorage persistence for articles and user
  • Per-article comments stored in Map by slug
  • User authentication persisted across page reloads
  • 12 sample articles for pagination testing
  • Default test user: [email protected] / 1234
  • Isolated state per article for comments
  • Realistic data with multiple authors and states

Retry Logic

  • Automatic retry with exponential backoff
  • Applied to all GET operations
  • 3 retries: 1s β†’ 2s β†’ 4s delays
  • Configurable per operation

State Management

  • Granular loading states per operation
  • Error handling with try/catch
  • State updates preserve loading/error states
  • Reactive updates with Signals

πŸ§ͺ Testing

# Run tests
npm run test

# Run tests with coverage
npm run test:coverage

# Run tests in watch mode
npm run test:watch

# Run E2E tests (Playwright)
npm run test:e2e

Test Coverage:

  • 120+ tests across 14 test files
  • 99.38% statement coverage
  • 94.37% branch coverage
  • 100% function coverage

Test Structure:

  • Unit Tests (Vitest): Core Services and Page Services
  • E2E Validation Tests (Vitest): Business logic flows at service level
  • E2E Tests (Playwright): Full UI integration tests

E2E Validation Tests (Service Level):

  • article-flows.e2e-validation.test.ts - Create, edit, delete, view articles
  • auth-flows.e2e-validation.test.ts - Registration and login
  • comments-flows.e2e-validation.test.ts - Create and delete comments
  • favorite-flows.e2e-validation.test.ts - Favorite and unfavorite articles
  • social-flows.e2e-validation.test.ts - Follow/unfollow users, view profiles
  • settings-flows.e2e-validation.test.ts - Update user profile, logout

πŸ› οΈ Development

# Install dependencies
npm install

# Start dev server (uses Mock API)
npm start

# Navigate to http://localhost:4200/

Mock API Mode

By default, the app runs with a Mock API in development mode:

  • No backend required
  • Instant responses (configurable delay)
  • Persistent state in localStorage
  • Perfect for frontend development

Real API Mode

To use the real backend API:

  1. Set environment.production = true in src/environments/environment.ts
  2. Configure API URL in Core Services
  3. Restart dev server

πŸ“¦ Build

# Production build
npm run build

# Build artifacts will be in dist/

πŸ“– Documentation

For detailed architecture documentation, see ARCHITECTURE.md

For migration guide and patterns, see MIGRATION-PROMPT.md

πŸŽ“ Key Concepts

PageState Pattern

All pages use a generic PageState<TData, TExtra> structure:

type PageState<TData, TExtra = {}> = {
  data: TData;                           // Core data
  loading: Record<string, boolean>;      // Loading states
  error: Record<string, string | null>;  // Error states
} & TExtra;                              // Page-specific metadata

Dependency Injection

Services are configured manually in main.ts without @Injectable():

const articlesApi = USE_MOCK 
  ? new MockArticlesApiService() 
  : new ArticlesApiService();

bootstrapApplication(AppComponent, {
  providers: [
    { provide: ArticlesApiService, useValue: articlesApi },
    { 
      provide: HomePageService, 
      useFactory: () => new HomePageService(articlesApi, tagsApi, userApi) 
    }
  ]
});

Component Pattern

Page Components act as adapters between Page Services and UI:

export class HomeComponent implements OnInit {
  private pageService = inject(HomePageService);
  
  state = signal<HomePageState>({
    data: { articles: [], tags: [], feeds: [] },
    loading: { initial: true },
    error: { initial: null }
  });

  ngOnInit() {
    this.pageService.init().then(state => this.state.set(state));
  }

  onFeedSelected(feed: Feed) {
    this.pageService
      .onFeedSelected({ feed, state: this.state() })
      .then(state => this.state.set(state));
  }
}

πŸ”„ Data Flow

  1. User interacts with UI Component
  2. UI Component emits event to Page Component
  3. Page Component calls Page Service method
  4. Page Service orchestrates Core Services
  5. Core Services call Backend API
  6. Data flows back through the layers
  7. Page Component updates Signal
  8. Template reactively updates UI

πŸ“ Code Quality

  • ESLint configured for Angular best practices
  • TypeScript strict mode enabled
  • No any types allowed
  • 100% test coverage on Page Services
  • Consistent naming conventions
  • Comprehensive error handling

πŸš€ Performance

  • Zoneless mode for better performance
  • Lazy-loaded routes for faster initial load
  • Standalone components reduce bundle size
  • Signals for efficient change detection
  • Retry logic for resilient API calls

πŸ“„ License

MIT


Version: 3.0.0
Last Updated: 2026-02-26
Status: βœ… Production Ready

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors