Skip to content

Commit ac98790

Browse files
committed
docs: update codebase instructions for react, fastapi, python, and typescript
Generated-by: aiautocommit
1 parent 7902070 commit ac98790

6 files changed

Lines changed: 129 additions & 27 deletions

File tree

.github/copilot-instructions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,24 @@ Coding instructions for all programming languages:
1111
- When I ask you to write code, prioritize simplicity and legibility over covering all edge cases, handling all errors, etc.
1212
- 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.
1313
- 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
14+
- 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`.
15+
16+
Use line breaks to organize code into logical groups. Instead of:
17+
18+
```python
19+
if not client_secret_id:
20+
raise HTTPException(status.HTTP_400_BAD_REQUEST)
21+
session_id = client_secret_id.split("_secret")[0]
22+
```
23+
24+
Prefer:
25+
26+
```python
27+
if not client_secret_id:
28+
raise HTTPException(status.HTTP_400_BAD_REQUEST)
29+
30+
session_id = client_secret_id.split("_secret")[0]
31+
```
1432

1533
**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.
1634

.github/instructions/fastapi.instructions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ applyTo: "app/routes/**/*.py"
33
---
44
## FastAPI
55

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

.github/instructions/python.instructions.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ When writing Python:
1515
* Log messages should be lowercase with no leading or trailing whitespace.
1616
* No variable interpolation in log messages.
1717
* Do not coerce database IDs or dates to strings
18-
* Do not worry about import ordering or other formatting issues.
18+
* Do not fix import ordering or other formatting issues.
1919

2020
### Date & DateTime
2121

@@ -26,6 +26,7 @@ When writing Python:
2626
When accessing database records:
2727

2828
* SQLModel (wrapping SQLAlchemy) is used
29+
* `Model.one(primary_key)` or `Model.get(primary_key)` should be used to retrieve a single record
2930
* Do not manage database sessions, these are managed by a custom tool
3031
* Use `TheModel(...).save()` to persist a record
3132
* Use `TheModel.where(...).order_by(...)` to query records. `.where()` returns a SQLAlchemy select object that you can further customize the query.
@@ -34,5 +35,32 @@ When writing database models:
3435

3536
* 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)`.
3637
* 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)
37-
* Use single double-quote docstrings (a string below the field definition) instead of comments to describe a field's purpose.
3838
* Use `ModelName.foreign_key()` when generating a foreign key field
39+
* Store currency as an integer, e.g. $1 = 100.
40+
41+
Example:
42+
43+
```python
44+
class Distribution(
45+
BaseModel, TimestampsMixin, SoftDeletionMixin, TypeIDMixin("dst"), table=True
46+
):
47+
"""Triple-quoted strings for multi-line class docstring"""
48+
49+
date_field_with_comment: datetime | None = None
50+
"use a string under the field to add a comment about the field"
51+
52+
# no need to add a comment about an obvious field; no need for line breaks if there are no field-level docstrings
53+
title: str = Field(unique=True)
54+
state: str
55+
56+
optional_field: str | None = None
57+
58+
# here's how relationships are constructed
59+
doctor_id: TypeIDType = Doctor.foreign_key()
60+
doctor: Doctor = Relationship()
61+
62+
@computed_field
63+
@property
64+
def order_count(self) -> int:
65+
return self.where(Order.distribution_id == self.id).count()
66+
```

.github/instructions/react-router.instructions.md

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,59 @@ applyTo: "web/app/routes/**/*.tsx"
33
---
44
## React Router
55

6+
- You are using the latest version of React Router (v7).
67
- 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`.
7-
- 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")`
8-
- Use `export async function clientLoader(loaderArgs: Route.ClientLoaderArgs)` to define a clientLoader on a route.
9-
- Use `loaderArgs.params.$THE_KEY` to use a query string parameter.
8+
- Use `href("/products/:id", { id: "abc123" })` to generate a url path for a route managed by the application.
9+
- Look at [routes.ts](mdc:web/app/routes.ts) to determine what routes and path parameters exist.
10+
- Use `export async function clientLoader(loaderArgs: Route.ClientLoaderArgs)` to define a `clientLoader` on a route.
1011
- Do not define `Route.*` types, these are autogenerated and can be imported from `import type { Route } from "./+types/routeFileName"`
11-
- Each non-layout route should define a meta function:
12+
- 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`
13+
- Never worry about generating types using `pnpm`
14+
- Use [`<AllMeta />`](web/app/components/shared/AllMeta.tsx) instead of MetaFunction or individual `<meta />` tags
15+
- Use the following pattern to reference query string values (i.e. `?theQueryStringParam=value`)
1216

1317
```typescript
14-
export const meta: MetaFunction = () => {
15-
return [
16-
{ title: "Page Title" },
17-
{
18-
name: "description",
19-
content: "Page Description",
20-
},
21-
]
18+
const [searchParams, _setSearchParams] = useSearchParams();
19+
// searchParams contains the value of all query string parameters
20+
const queryStringValue = searchParams.get("theQueryStringParam")
21+
```
22+
23+
### Loading Mock Data
24+
25+
Don't load mock data in the component function with `useEffect`. Instead, load data in a `clientLoader`:
26+
27+
```typescript
28+
29+
// in mock.ts
30+
export async function getServerData(options: any) {
31+
// ...
32+
}
33+
34+
// in web/app/routes/**/*.ts
35+
export async function clientLoader(loaderArgs: Route.ClientLoaderArgs) {
36+
// no error reporting is needed, this will be handled by the `getServerData`
37+
// mock loading functions should return result in a `data` key
38+
const { data } = await getServerData({ /* ... */ })
39+
40+
// the return result here is available in `loaderData`
41+
return data
2242
}
2343
```
2444

45+
### How to use clientLoader
46+
47+
- `export async function clientLoader(loaderArgs: Route.ClientLoaderArgs) {`
48+
- Load any server data required for page load here, not in the component function.
49+
- Use `return redirect(href("/the/url"))` to redirect users
50+
- Use [getQueryParam](web/app/lib/utils.ts) to get query string variables
51+
- `throw new Response` if you need to mimic a 400, 500, etc error
52+
- `loaderArgs` and all sub-objects are all fully typed
53+
- `loaderArgs.params.id` to get URL parameters
54+
2555
### Using API Data
2656

27-
* `~/configuration/client` re-exports all types and functions from `client/*`. Import from `~/configuration/client` instead of anything you find in the `client/` folder/package.
28-
* 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.
57+
- `~/configuration/client` re-exports all types and functions from `client/*`. Import from `~/configuration/client` instead of anything you find in the `client/` folder/package.
58+
- 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.
59+
- When using an import from `~/configuration/client`:
60+
- use `body:` for request params
61+
- always `const { data, error } = await theCall()`

.github/instructions/react.instructions.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,51 @@ applyTo: "**/*.tsx"
33
---
44
## React
55

6+
- You are using the latest version of React (v19)
67
- Do not write any backend code. Just frontend logic.
7-
- For any backend requirements, create mock responses. Use a function to return mock data so I can easily swap it out later.
8-
- When creating mock data, always specify it in a dedicated `mock.ts` file
9-
- Load mock data using a react router `clientLoader`. Use the Skeleton component to present a loading state.
108
- If a complex skeleton is needed, create a component function `LoadingSkeleton` in the same file.
11-
- Store components for each major page or workflow in `src/components/$WORKFLOW_OR_PAGE_NAME`.
9+
- Store components for each major page or workflow in `app/components/$WORKFLOW/$COMPONENT.tsx`.
10+
- If a single page has more than two dedicated components, create a subfolder `app/components/$WORKFLOW/$PAGE/$COMPONENT.tsx`
1211
- Use lowercase dash separated words for file names.
1312
- Use React 19, TypeScript, Tailwind CSS, and ShadCN components.
1413
- Prefer function components, hooks over classes.
14+
- Use ShadCN components in `web/app/components/ui` as your component library. If you need new components, ask for them.
15+
- Never edit the `web/components/ui/*.tsx` files.
16+
- You can find a list of components here https://ui.shadcn.com/docs/components
1517
- Break up large components into smaller components, but keep them in the same file unless they can be generalized.
1618
- Put any "magic" strings like API keys, hosts, etc into a "constants.ts" file.
17-
- Only use a separate interface for component props if there are more than 4 props.
18-
- Put the interface definition right above the related function
19+
- 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.
20+
- Put the interface definition right above the related function
1921
- Internally, store all currency values as integers and convert them to floats when rendering visually
20-
- Never edit (or add) `components/ui/*.tsx` files
2122
- When building forms use React Hook Form.
2223
- Include a two line breaks between any `useHook()` calls and any `useState()` definitions for a component.
23-
- Use `href("/products/:id", { id: "abc123" })` to generate a url path for a route managed by the application.
24-
- Look at @routes.ts to determine what routes and path parameters exist.
24+
- 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
25+
- Use the following pattern to reference query string values (i.e. `?theQueryStringParam=value`):
26+
27+
```typescript
28+
const [searchParams, _setSearchParams] = useSearchParams();
29+
// searchParams contains the value of all query string parameters
30+
const queryStringValue = searchParams.get("theQueryStringParam")
31+
```
32+
33+
### Mock Data
34+
35+
- 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.
36+
- When creating mock data, always specify it in a dedicated `web/app/mock.ts` file
37+
- Load mock data using a react router `clientLoader`. Use the Skeleton component to present a loading state.
2538

2639
### React Hook Form
2740

2841
Follow this structure when generating a form.
2942

3043
```tsx
44+
45+
// add a mock function simulating server communication
46+
async function descriptiveServerSendFunction(values: any) {
47+
const mockData = getMockReturnData(/* ... */)
48+
return new Promise(resolve => setTimeout(() => resolve(mockData), 500));
49+
}
50+
3151
const formSchema = z.object({
3252
field_name: z.string(),
3353
// additional schema definition
@@ -39,6 +59,8 @@ const form = useForm<z.infer<typeof formSchema>>({
3959

4060
async function onSubmit(values: z.infer<typeof formSchema>) {
4161
// ...
62+
await descriptiveSendFunction(values)
63+
// ...
4264
}
4365

4466
return (

.github/prompts/typescript-docstring.prompt.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ description: ''
44
---
55
## TypeScript DocString
66

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

0 commit comments

Comments
 (0)