Skip to content
advanced Phase 16 · TypeScript Capstone Project

Capstone: Project Planning

Plan a full stack TypeScript project with proper folder structure.

1h
0 problems
Topic Progress 0%

From Requirements to Boundaries

From Requirements to Boundaries

Architecture starts with the write paths: list the entities that change (orders, users, files), the operations on them, and who calls them. Each cluster of behavior that changes for one reason becomes a module:

apps/web          # UI, talks only to apps/api
apps/api          # HTTP layer: routing, auth, validation
packages/shared   # types + validation schemas shared by both

The HTTP layer stays thin: parse, authorize, delegate, serialize. Domain logic lives where it can be unit-tested without a socket. Rules worth writing down: apps/* may import packages/*, never the reverse, and no two packages import each other — a cycle means the boundary is wrong.

Folder Structure and Module Rules

Folder Structure and Module Rules

Feature-first structure keeps related files together and makes ownership obvious:

apps/api/src/
  modules/orders/
    routes.ts     # transport only
    service.ts    # business rules
    repo.ts       # persistence
    orders.test.ts
  lib/            # cross-cutting: db, logger, config

Rules that keep it healthy: import across features only through service.ts or a shared package; keep lib/ free of feature knowledge; colocate tests with code. Declare the policy in tooling — ESLint no-restricted-imports or dependency-cruiser — because folder conventions without enforcement rot within a quarter.

Data Flow and Pitfalls

Data Flow and Pitfalls

Decide now: server state (fetched, cached, mutated) versus client UI state, and which layer owns each. A common plan: API returns plain JSON shaped like shared types; the client keeps server data in a query cache (React Query/SWR) and UI state in local stores; validation schemas in shared guard both ends.

Pitfalls. Premature microservices — network boundaries replace type checking with retries; start as one deployable with internal modules. Duplicated types between frontend and backend drift silently — generate or share them. Leaking database rows as API responses couples clients to schema.

Interview: draw the request path, name each package's one responsibility, and defend a boundary you would NOT split yet.

Quiz

1. Where should business rules live in a layered full-stack app?

Question 1 options

2. What does "apps may import packages, never the reverse" prevent?

Question 2 options

3. When are two packages importing each other a design problem?

Question 3 options

Flashcards

Question

Dependency rule

Answer

Inner packages know nothing of outer ones; apps → packages only, cycles forbidden.

Question

Feature-first structure

Answer

routes/service/repo/test per feature under one folder; lib holds only cross-cutting code.

Question

Server vs client state

Answer

Fetched data belongs in a query cache; ephemeral UI state in local stores.

Question

Premature microservice

Answer

Splitting before boundaries are stable, trading type checks for network failure modes.

Revision Notes

Key Takeaways

  • 1. Boundaries follow reasons to change, not file-count aesthetics
  • 2. Enforce import rules in lint config, not tribal knowledge
  • 3. Share types/schemas from one package; never hand-copy them

Interview Tips

  • • Walk a request end to end and name the single responsibility of each folder
  • • Present one boundary you deliberately kept merged and the trigger to split it later

Cheat Sheet

apps/* → packages/shared, no cycles; feature folder = routes/service/repo/test; API returns shared types; query cache for server state; enforce imports via ESLint.

Continue Learning