Error handling improvements for fullstack project
This issue pertains to the fullstack project located in src/projects/fullstack. We need a deep, comprehensive overhaul of how we handle capturing errors. We need improved patterns, deeper modules, and scalable solutions as the codebase grows.
ErrorContext schema
src/projects/fullstack/src/shared/types.d.ts
The ErrorContext schema lists all the possible errors throughout the application. Hence, it's stored in the shared folder since errors can happen on the client or server.
The ErrorContext union uses a 2-part schema broken up by a colon in the form of <service>:<operation><Suffix>. However, this really encoding 3 parts. This needs to change to <service>:<operation>:<suffix>.
Are these actually errors to begin with?
Not everything that "goes wrong" should be an error. For example, ErrorContext has a union value of client:signInRejection. This can happen if you enter a wrong password. That is the expected user experience - enter an incorrect password, you (visually) get an error. Do we need to save that to the database? We need a review of all the ErrorContext union values to see if each of these scenarios qualifies as a bonafide error that should be saved to the database.
Saving errors to the database
The suffix in the ErrorContext schema is either Rejection (which means the API rejected the request and sent back an error) or Exception (which means the request failed, such as network failure, aborted request, etc). The Exception cases are rightly the domain of the client. However, the Rejection cases are mostly an inefficient round trip from server → client → server. The current flow for most Rejection's goes:
client request → server responds with error → client receives error & sends it back to the server to /api/client-error
There's a number of things wrong with this approach:
- The name of the endpoint -
/api/client-error. While the error is being POSTed from the client, these aren't strictly client-only errors.
- This is an unnecessary round trip. If the server already has the error, the server should be responsible for saving it to the db.
Logging is an overloaded term
The term "logging" in reference to saving errors in the database is confusing and overlaps other domains, such as logging errors to the console (which we already have a module which logs errors to the console import {createLogger} from '@qodestack/utils'). We need a more accurate, descriptive term. Sentry uses the term "capture". So something like captureError(...) might do better.
Deepening the module
Deep modules comes from "A Philosophy of Software Design." The idea is simple: lots of implementation controlled by a simple interface. I believe both the current client and server side error functionality are candidates for benefitting from deep modules. There's a decent amount of ceremony around the current setup and it feels like a code smell.
On the client side, we perform the same ceremony in multiple places. This feels like a candidate for a more centralized, deepened error module, to alleviate consumers from having to write unnecessary code. We need to look for wins here.
On the server side, I'd say we need to establish a deep module also. As mentioned before, the server is already offloading error logging to the client side. That should be the server's responsibility.
Updating SKILLS.md accordingly
There are a number of skills that provide guidance for agents when working in this fullstack app. All of them can be found in src/projects/fullstack/.claude-keep/skills. These need to be updated according to any changes we make. These skills need to accurately reflect how the codebase works and is organized.
Error handling improvements for fullstack project
This issue pertains to the fullstack project located in
src/projects/fullstack. We need a deep, comprehensive overhaul of how we handle capturing errors. We need improved patterns, deeper modules, and scalable solutions as the codebase grows.ErrorContextschemasrc/projects/fullstack/src/shared/types.d.tsThe
ErrorContextschema lists all the possible errors throughout the application. Hence, it's stored in the shared folder since errors can happen on the client or server.The
ErrorContextunion uses a 2-part schema broken up by a colon in the form of<service>:<operation><Suffix>. However, this really encoding 3 parts. This needs to change to<service>:<operation>:<suffix>.Are these actually errors to begin with?
Not everything that "goes wrong" should be an error. For example,
ErrorContexthas a union value ofclient:signInRejection. This can happen if you enter a wrong password. That is the expected user experience - enter an incorrect password, you (visually) get an error. Do we need to save that to the database? We need a review of all theErrorContextunion values to see if each of these scenarios qualifies as a bonafide error that should be saved to the database.Saving errors to the database
The
suffixin theErrorContextschema is eitherRejection(which means the API rejected the request and sent back an error) orException(which means the request failed, such as network failure, aborted request, etc). TheExceptioncases are rightly the domain of the client. However, theRejectioncases are mostly an inefficient round trip from server → client → server. The current flow for mostRejection's goes:client request → server responds with error → client receives error & sends it back to the server to
/api/client-errorThere's a number of things wrong with this approach:
/api/client-error. While the error is beingPOSTed from the client, these aren't strictly client-only errors.Logging is an overloaded term
The term "logging" in reference to saving errors in the database is confusing and overlaps other domains, such as logging errors to the console (which we already have a module which logs errors to the console
import {createLogger} from '@qodestack/utils'). We need a more accurate, descriptive term. Sentry uses the term "capture". So something likecaptureError(...)might do better.Deepening the module
Deep modules comes from "A Philosophy of Software Design." The idea is simple: lots of implementation controlled by a simple interface. I believe both the current client and server side error functionality are candidates for benefitting from deep modules. There's a decent amount of ceremony around the current setup and it feels like a code smell.
On the client side, we perform the same ceremony in multiple places. This feels like a candidate for a more centralized, deepened error module, to alleviate consumers from having to write unnecessary code. We need to look for wins here.
On the server side, I'd say we need to establish a deep module also. As mentioned before, the server is already offloading error logging to the client side. That should be the server's responsibility.
Updating SKILLS.md accordingly
There are a number of skills that provide guidance for agents when working in this fullstack app. All of them can be found in
src/projects/fullstack/.claude-keep/skills. These need to be updated according to any changes we make. These skills need to accurately reflect how the codebase works and is organized.