Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions docs/Sustainability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Sustainability choices

We have made several choices that help reduce unnecessary data transfer, processing,
and storage. In this context, sustainability means using fewer computing resources
while still providing the required functionality and a responsive user experience.

## Reducing data transfer

### Cursor-based pagination

The GraphQL API uses cursor-based pagination to retrieve Pokémon in small pages
instead of loading the entire dataset at once. The server limits each request to
100 results and returns an `endCursor` together with page indicators. The client
can then request the next part of the dataset when the user navigates.

This reduces the amount of data transferred and processed for each interaction,
especially when searching or browsing a larger dataset. It also avoids making
the browser render hundreds of cards that the user may never view. The
implementation is in `project2/server/schema.ts` and is used by the query in
`project2/src/App.tsx`.

### Server-side search, filtering, and sorting

Search, type filtering, and sorting are performed by the GraphQL server and
translated into database queries. The client therefore receives only the
matching page of results instead of downloading the complete dataset and
filtering it in the browser. This reduces both network traffic and client-side
processing.

### Apollo client cache

The frontend uses Apollo Client's `InMemoryCache`. Responses can be reused by
Apollo when the same query data is requested again, which can reduce repeated
requests and processing during a browsing session. The cache is configured in
`project2/src/main.tsx`.

## Reducing processing and storage

### SQLite database

SQLite stores the application's data in a single lightweight database file. This
avoids the overhead of running a separate database server for this project while
still providing structured queries through Apollo GraphQL. A local database is
appropriate for the project's scale and deployment model, where a separate
database service would add operational and resource overhead.

### Relational data structure

Pokémon, abilities, types, and ratings are stored in separate related tables.
Separating these concerns keeps the main Pokémon records focused and allows
ratings to be updated without rewriting the rest of a Pokémon record. Foreign
keys and a composite primary key for ratings also prevent invalid or duplicate
rating records.

This is a relational structure rather than complete deduplication: ability and
type values are currently stored in rows associated with each Pokémon. Further
normalization could reduce repeated names if the dataset grows substantially.
The schema and constraints are defined in `project2/server/db.ts`.

### Seed-once database initialization

The server checks whether the database already contains Pokémon before fetching
and inserting seed data. Existing data is reused on later starts, avoiding
repeated API requests and repeated processing. This behavior is implemented in
`project2/server/index.ts` and `project2/server/db.ts`.

## Trade-offs and limitations

These choices reduce unnecessary work for the current project, but they do not
eliminate resource usage:

- The initial seed can still require a relatively large external API request.
- Pokémon images are loaded from an external image URL and are not currently
documented as having responsive variants or lazy loading.
- SQLite is lightweight for this deployment, but a larger multi-user system
could require a database service with stronger concurrency and scaling
characteristics.
- The current pagination API is forward-oriented: it exposes `after` and
`hasPreviousPage`, but does not expose a `before` or `last` argument for
directly requesting a previous page.

## Possible future improvements

If the dataset or traffic increases, we could measure and improve the system by:

- adding indexes for the most common search, filter, and sort queries;
- lazy-loading images and serving appropriately sized image variants;
- caching seed data or using a controlled import process to reduce startup
requests;
- recording representative payload sizes, request counts, database size, and
load times to evaluate the effect of future changes.