Skip to content

Commit 7902070

Browse files
committed
docs: clarify coding standards for naming, spacing, DB, React, mocks
- Expanded variable and function naming guidance to prioritize descriptive effect-based names - Added explicit instructions for code organization, line breaks, and inline field comments in Python and React - Updated mock data setup and loader use for frontend, reinforced guidelines for file placement, prop typing, and component structure - Clarified use of FastAPI, database access patterns, React Router usage, and integration of ShadCN components - Emphasized separation of backend/frontend, currency handling, and explicit behaviors for exceptions and server communication Generated-by: aiautocommit
1 parent 194d558 commit 7902070

1 file changed

Lines changed: 133 additions & 27 deletions

File tree

instructions.md

Lines changed: 133 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ Coding instructions for all programming languages:
1010
- When I ask you to write code, prioritize simplicity and legibility over covering all edge cases, handling all errors, etc.
1111
- When a particular need can be met with a mature, reasonably adopted and maintained package, I would prefer to use that package rather than engineering my own solution.
1212
- Never add error handling to recover gracefully from an error without being asked to do so. Fail hard and early with assertions and allowing exceptions to propagate whenever possible
13+
- When naming variables or functions, use names that describe the effect. For example, instead of `function handleClaimFreeTicket` (a function which opens a dialog box) use `function openClaimFreeTicketDialog`.
14+
15+
Use line breaks to organize code into logical groups. Instead of:
16+
17+
```python
18+
if not client_secret_id:
19+
raise HTTPException(status.HTTP_400_BAD_REQUEST)
20+
session_id = client_secret_id.split("_secret")[0]
21+
```
22+
23+
Prefer:
24+
25+
```python
26+
if not client_secret_id:
27+
raise HTTPException(status.HTTP_400_BAD_REQUEST)
28+
29+
session_id = client_secret_id.split("_secret")[0]
30+
```
1331

1432
**DO NOT FORGET**: keep your responses short, dense, and without fluff. I am a senior, well-educated software engineer, and do not need long explanations.
1533

@@ -32,7 +50,7 @@ When writing Python:
3250
* Log messages should be lowercase with no leading or trailing whitespace.
3351
* No variable interpolation in log messages.
3452
* Do not coerce database IDs or dates to strings
35-
* Do not worry about import ordering or other formatting issues.
53+
* Do not fix import ordering or other formatting issues.
3654

3755
### Date & DateTime
3856

@@ -43,6 +61,7 @@ When writing Python:
4361
When accessing database records:
4462

4563
* SQLModel (wrapping SQLAlchemy) is used
64+
* `Model.one(primary_key)` or `Model.get(primary_key)` should be used to retrieve a single record
4665
* Do not manage database sessions, these are managed by a custom tool
4766
* Use `TheModel(...).save()` to persist a record
4867
* Use `TheModel.where(...).order_by(...)` to query records. `.where()` returns a SQLAlchemy select object that you can further customize the query.
@@ -51,8 +70,35 @@ When writing database models:
5170

5271
* Don't use `Field(...)` unless required (i.e. when specifying a JSON type for a `dict` or pydantic model using `Field(sa_type=JSONB)`). For instance, use `= None` instead of `= Field(default=None)`.
5372
* Add enum classes close to where they are used, unless they are used across multiple classes (then put them at the top of the file)
54-
* Use single double-quote docstrings (a string below the field definition) instead of comments to describe a field's purpose.
5573
* Use `ModelName.foreign_key()` when generating a foreign key field
74+
* Store currency as an integer, e.g. $1 = 100.
75+
76+
Example:
77+
78+
```python
79+
class Distribution(
80+
BaseModel, TimestampsMixin, SoftDeletionMixin, TypeIDMixin("dst"), table=True
81+
):
82+
"""Triple-quoted strings for multi-line class docstring"""
83+
84+
date_field_with_comment: datetime | None = None
85+
"use a string under the field to add a comment about the field"
86+
87+
# no need to add a comment about an obvious field; no need for line breaks if there are no field-level docstrings
88+
title: str = Field(unique=True)
89+
state: str
90+
91+
optional_field: str | None = None
92+
93+
# here's how relationships are constructed
94+
doctor_id: TypeIDType = Doctor.foreign_key()
95+
doctor: Doctor = Relationship()
96+
97+
@computed_field
98+
@property
99+
def order_count(self) -> int:
100+
return self.where(Order.distribution_id == self.id).count()
101+
```
56102

57103
## Python App
58104

@@ -79,35 +125,56 @@ When writing database models:
79125

80126
## Fastapi
81127

82-
- When generating a HTTPException, do not add a `detail=` and use a named status code (`status.HTTP_400_BAD_REQUEST`)
128+
- When throwing a `HTTPException`, do not add a `detail=` and use a named status code (`status.HTTP_400_BAD_REQUEST`)
129+
- Do not return a `dict`, instead create a `class RouteNameResponse`
83130

84131
## React
85132

133+
- You are using the latest version of React (v19)
86134
- Do not write any backend code. Just frontend logic.
87-
- For any backend requirements, create mock responses. Use a function to return mock data so I can easily swap it out later.
88-
- When creating mock data, always specify it in a dedicated `mock.ts` file
89-
- Load mock data using a react router `clientLoader`. Use the Skeleton component to present a loading state.
90135
- If a complex skeleton is needed, create a component function `LoadingSkeleton` in the same file.
91-
- Store components for each major page or workflow in `src/components/$WORKFLOW_OR_PAGE_NAME`.
136+
- Store components for each major page or workflow in `app/components/$WORKFLOW/$COMPONENT.tsx`.
137+
- If a single page has more than two dedicated components, create a subfolder `app/components/$WORKFLOW/$PAGE/$COMPONENT.tsx`
92138
- Use lowercase dash separated words for file names.
93139
- Use React 19, TypeScript, Tailwind CSS, and ShadCN components.
94140
- Prefer function components, hooks over classes.
141+
- Use ShadCN components in `web/app/components/ui` as your component library. If you need new components, ask for them.
142+
- Never edit the `web/components/ui/*.tsx` files.
143+
- You can find a list of components here https://ui.shadcn.com/docs/components
95144
- Break up large components into smaller components, but keep them in the same file unless they can be generalized.
96145
- Put any "magic" strings like API keys, hosts, etc into a "constants.ts" file.
97-
- Only use a separate interface for component props if there are more than 4 props.
98-
- Put the interface definition right above the related function
146+
- For React functional components with three or fewer props, always inline the prop types as an object literal directly in the function signature after the destructured parameters (e.g., `function Component({ prop1, prop2 }: { prop1: string; prop2?: number }) { ... })`. Include default values in destructuring and mark optional props with ? in the type object. Do not use separate interfaces or type aliases; keep types inline. For complex types, add inline comments if needed.
147+
- Put the interface definition right above the related function
99148
- Internally, store all currency values as integers and convert them to floats when rendering visually
100-
- Never edit (or add) `components/ui/*.tsx` files
101149
- When building forms use React Hook Form.
102150
- Include a two line breaks between any `useHook()` calls and any `useState()` definitions for a component.
103-
- Use `href("/products/:id", { id: "abc123" })` to generate a url path for a route managed by the application.
104-
- Look at @routes.ts to determine what routes and path parameters exist.
151+
- When using a function prop inside a `useEffect`, please use a pattern that avoids including the function in the dependency array, like the `useRef` trick.s
152+
- Use the following pattern to reference query string values (i.e. `?theQueryStringParam=value`):
153+
154+
```typescript
155+
const [searchParams, _setSearchParams] = useSearchParams();
156+
// searchParams contains the value of all query string parameters
157+
const queryStringValue = searchParams.get("theQueryStringParam")
158+
```
159+
160+
### Mock Data
161+
162+
- For any backend communication, create mock responses. Use a async function to return mock data that I will swap out later for a async call to an API.
163+
- When creating mock data, always specify it in a dedicated `web/app/mock.ts` file
164+
- Load mock data using a react router `clientLoader`. Use the Skeleton component to present a loading state.
105165

106166
### React Hook Form
107167

108168
Follow this structure when generating a form.
109169

110170
```tsx
171+
172+
// add a mock function simulating server communication
173+
async function descriptiveServerSendFunction(values: any) {
174+
const mockData = getMockReturnData(/* ... */)
175+
return new Promise(resolve => setTimeout(() => resolve(mockData), 500));
176+
}
177+
111178
const formSchema = z.object({
112179
field_name: z.string(),
113180
// additional schema definition
@@ -119,6 +186,8 @@ const form = useForm<z.infer<typeof formSchema>>({
119186

120187
async function onSubmit(values: z.infer<typeof formSchema>) {
121188
// ...
189+
await descriptiveSendFunction(values)
190+
// ...
122191
}
123192

124193
return (
@@ -132,29 +201,62 @@ return (
132201

133202
## React Router
134203

204+
- You are using the latest version of React Router (v7).
135205
- The primary export in a routes file should specify `loaderData` like `export default function RouteNamePage({ loaderData }: Route.ComponentProps)`. `loaderData` is the return value from `clientLoader`.
136-
- When using an import from `~/configuration/client` (1) use `body:` for request params and (2) always `const { data, error } = await theCall()` (3) add `invariant(data, "error loading $xyz")`
137-
- Use `export async function clientLoader(loaderArgs: Route.ClientLoaderArgs)` to define a clientLoader on a route.
138-
- Use `loaderArgs.params.$THE_KEY` to use a query string parameter.
206+
- Use `href("/products/:id", { id: "abc123" })` to generate a url path for a route managed by the application.
207+
- Look at [routes.ts](mdc:web/app/routes.ts) to determine what routes and path parameters exist.
208+
- Use `export async function clientLoader(loaderArgs: Route.ClientLoaderArgs)` to define a `clientLoader` on a route.
139209
- Do not define `Route.*` types, these are autogenerated and can be imported from `import type { Route } from "./+types/routeFileName"`
140-
- Each non-layout route should define a meta function:
210+
- If URL parameters or query string values need to be checked before rendering the page, do this in a `clientLoader` and not in a `useEffect`
211+
- Never worry about generating types using `pnpm`
212+
- Use [`<AllMeta />`](web/app/components/shared/AllMeta.tsx) instead of MetaFunction or individual `<meta />` tags
213+
- Use the following pattern to reference query string values (i.e. `?theQueryStringParam=value`)
141214

142215
```typescript
143-
export const meta: MetaFunction = () => {
144-
return [
145-
{ title: "Page Title" },
146-
{
147-
name: "description",
148-
content: "Page Description",
149-
},
150-
]
216+
const [searchParams, _setSearchParams] = useSearchParams();
217+
// searchParams contains the value of all query string parameters
218+
const queryStringValue = searchParams.get("theQueryStringParam")
219+
```
220+
221+
### Loading Mock Data
222+
223+
Don't load mock data in the component function with `useEffect`. Instead, load data in a `clientLoader`:
224+
225+
```typescript
226+
227+
// in mock.ts
228+
export async function getServerData(options: any) {
229+
// ...
230+
}
231+
232+
// in web/app/routes/**/*.ts
233+
export async function clientLoader(loaderArgs: Route.ClientLoaderArgs) {
234+
// no error reporting is needed, this will be handled by the `getServerData`
235+
// mock loading functions should return result in a `data` key
236+
const { data } = await getServerData({ /* ... */ })
237+
238+
// the return result here is available in `loaderData`
239+
return data
151240
}
152241
```
153242

243+
### How to use clientLoader
244+
245+
- `export async function clientLoader(loaderArgs: Route.ClientLoaderArgs) {`
246+
- Load any server data required for page load here, not in the component function.
247+
- Use `return redirect(href("/the/url"))` to redirect users
248+
- Use [getQueryParam](web/app/lib/utils.ts) to get query string variables
249+
- `throw new Response` if you need to mimic a 400, 500, etc error
250+
- `loaderArgs` and all sub-objects are all fully typed
251+
- `loaderArgs.params.id` to get URL parameters
252+
154253
### Using API Data
155254

156-
* `~/configuration/client` re-exports all types and functions from `client/*`. Import from `~/configuration/client` instead of anything you find in the `client/` folder/package.
157-
* For each API endpoint, there's a fully typed async function that can be used to call it. Never attempt to call an API endpoint directly.
255+
- `~/configuration/client` re-exports all types and functions from `client/*`. Import from `~/configuration/client` instead of anything you find in the `client/` folder/package.
256+
- For each API endpoint, there's a fully typed async function that can be used to call it. Never attempt to call an API endpoint directly.
257+
- When using an import from `~/configuration/client`:
258+
- use `body:` for request params
259+
- always `const { data, error } = await theCall()`
158260

159261
## React Router Client Loader
160262

@@ -174,7 +276,7 @@ Do this in a `clientLoader` and use `loaderData` to render the component. DO NOT
174276

175277
## Typescript Docstring
176278

177-
Add a file-level docstring with a simple description of what this file does.
279+
Add a file-level docstring with a simple description of what this file does and where this is used.
178280

179281
## Secrets
180282

@@ -191,3 +293,7 @@ Here's how environment variables are managed in this application:
191293
- `*.local` files have a `-example` variant which is committed to version control. These document helpful environment variables for local development.
192294
- When writing TypeScript/JavaScript/React, use `requireEnv("THE_ENV_VAR_NAME")` to read an environment variable. `import {requireEnv} from '~/utils/environment'`
193295

296+
## Refactor On Instructions
297+
298+
Refactor this code following all the established coding rules. Carefully review each rule.
299+

0 commit comments

Comments
 (0)