mirror of
				https://github.com/datahub-project/datahub.git
				synced 2025-11-03 20:27:50 +00:00 
			
		
		
		
	
		
			
				
	
	
	
		
			8.1 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	
			8.1 KiB
		
	
	
	
	
	
	
	
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this directory. It also contains our style guide, which can be consumed by engineers.
Style Guide
File Structure
- What should our top-level folders be?
app: components that implement the entire application- Based on nav page
 - Each new high-level page gets a new top-level folder
 - Nested pages are within the same top-level folder
 
graphql: graphql files and generated typesimages: all custom imagesconf/fonts/providers/utils: do we need these?- When do we create a new one?
 
 - What to put in 
index.ts(x)?- Do not create these files
 
 - Where to put tests?
- In 
__tests__/in the same directory as the file - Named 
OriginalFile.test.ts(x) 
 - In 
 - Where to put utils?
- For utils used in a single file: 
SourceFile.utils.ts - For utils used in a folder: 
folderName/folderName.utils.ts 
 - For utils used in a single file: 
 - Where to put hooks?
- For helper hooks used in a single file: 
SourceFile.hooks.ts(x) - For standalone, reusable hooks: 
hookName.ts(x) - Try not to write hooks that generate JSX, but sometimes it may make sense
 
 - For helper hooks used in a single file: 
 - Where to put types?
- Types only used once should be in the same file where they’re used
 - Shared types go in 
folderName/folderName.types.ts 
 - Where to put helper components?
- If the component is only used once and is small: 
parent/SourceFile.components.tsx- e.g. 
search/SearchPage.components.tsx 
 - e.g. 
 - If a component is shared / large and doesn’t have its own children: 
parent/NewComponent.tsx- e.g. 
search/SearchPageHeader.tsx 
 - e.g. 
 - If the component has its own child components, put it in a new folder:
parent/NewComponent/NewComponent.tsx- e.g. 
search/SearchCard/SearchCard.tsx 
 - e.g. 
 
 - If the component is only used once and is small: 
 
Component Library
- What is an DataHub component? (previously: alchemy component)
- Can be reused anywhere in the app
 - Generalized
- Doesn’t depend on our aspect / data structure
 - Doesn’t depend on graphql types
 
 
 - Where do reusable non-DataHub components go?
- e.g. 
EntityHealthicon,HoverEntityTooltip- Can be reused anywhere within the web app
 - Not general: can take in very DataHub/gms specific inputs, e.g. graphql types
 
 - shared/
- components/
- entity/
entity.types.ts- health/
EntityHealth
 - tooltip
HoverEntityTooltip
 
 - button/
DownloadSearchResultsButton
 
 - entity/
 - hooks/
 - utils/
 
 - components/
 
 - e.g. 
 
Code Structure
- When to break into a new component?
- We should err on the side of more and smaller components (files)
 - When JSX is getting too large or complex
 - Any logical or reusable chunk
 
 - When to break into a hook?
- When a component’s logic is getting too large or complex
 - Any logical or reusable chunk of logic
 
 - When to use a React context vs passing props?
- Err on the side of not creating contexts — only add when necessary
 - Globally: use a context when we want values available globally, e.g. 
AppContextorUserContext - Low-level, small-scope: use a tightly-defined context for a small, self-contained set of files
folder/<Folder>Context.ts- Contains type, default value, helper hooks
 
folder/<Folder>ContextProvider.tsx- Contains just the provider
 
 - TBD: How to handle contexts for entity components?
shared/entity/EntityContext.tsx?
 
 - How to pass props?
- For small amount of props, can use individual values
 - When props gets larger, try to break into logical pieces
- e.g. 
entityDatarather than individual props for each aspect of the entity 
 - e.g. 
 - For components reused between OSS and SaaS:
- SaaS-only props should go in a single field: 
acrylProps: { ... } 
 - SaaS-only props should go in a single field: 
 
 - Component file sections:
- Imports
 - Constants (in SNAKE_CASE)
 - Styled components
 - Props
 - Main component
 
 
Code Conventions
- How to pass styles to a component?
- Use styled components for any simple components
 - For custom components (e.g. our DataHub components), take 
classNamein as a prop and pass it to the top-level element — whatever it makes sense for custom styles to be applied to- This allows us to pass styles by styled component inheritance
- e.g. if there’s a custom component 
Button, this allows us to defineconst CustomButton = styled(Button) 
 - e.g. if there’s a custom component 
 
 - This allows us to pass styles by styled component inheritance
 - If there are multiple elements for which custom styles can be applied, non-top-level ones should be passed as a CSSProperties prop, with a specific name, e.g. 
textStyleorbuttonStyle 
 - How to handle images and icons
- For component library icons, use 
<Icon>DataHub component and specify color and size via props- If size is not known, use 
size="inherit"and setfont-sizein parent div - Always use phosphor icons — ant and material ui icons are deprecated
 
 - If size is not known, use 
 - For custom images, use 
<Image>(once it’s built) and specify color and size via props- For svgs, in svg definition, set 
fill="currentColor"and then … TODO - Alt text should be a required field
 
 - For svgs, in svg definition, set 
 
 - For component library icons, use 
 - How to do theming?
- Use 
styled-componentstheming, with stringed css rather than object css 
 - Use 
 - React Components: Use TypeScript interfaces for props instead of PropTypes (which are deprecated)
 
// YES
styled.div`
    border-radius: 2px;
`;
// NO
styled.div({ borderRadius: '2px' });
Code Style
Mostly handled by linter and formatter (prettier). Mostly unimportant changes that we should be consistent on to improve readability.
- Functions vs lambdas
- Top-level, prefer named functions (
export default function f() { }) - Nested, use lambdas (
const onClick = () => { }) 
 - Top-level, prefer named functions (
 - Prefer 
typeoverinterface(except when using classes) - When to omit types
- For variables, do not need to specify
 - For function signatures, try to specify, unless it’s too difficult. In that case, prefer inferred typing over 
any - Prefer a mapper function over unsafe type casting
- If you must cast types, do so as early (high) as possible
 
 
 - Prefer destructuring over dot notation, but use your own intuition
- When accessing arrays, always option chain (i.e. 
x?.[0]) 
 - When accessing arrays, always option chain (i.e. 
 - When to optional chain
- If it type checks, it should be fine, except for the array access case above
 
 - Prefer direct imports, e.g. 
import React, { useState } from 'react'overReact.useState 
Development Commands
Setup and Dependencies
# Install dependencies and set up dev environment
# Update dependencies after changes to package.json
../gradlew yarnInstall
Running the Service
# Local development on localhost:3000 (with hot reload)
../gradlew yarnServe
# Development with remote GMS (e.g., dev01)
../gradlew yarnPreview -Pproxy="<remote-instance-url>"
# e.g. ../gradlew yarnPreview -Pproxy="https://dev01.acryl.io/"
Testing and Code Quality
Run formatting / linting / type checking / relevant tests after all changes
# Generate ts files based on graphql
yarn generate
# Run formatting
yarn format
# Run linting on all files
../gradlew yarnLint
# Run lint-fix on a single file
../gradlew -x yarnInstall -x yarnGenerate yarnLintFix -Pfile=src/path/to/file.tsx
# Run linting on a single file
# This does not run full type-check when we run for a single file
# that should be run at the end of all changes before commit
../gradlew -x yarnInstall -x yarnGenerate yarnLint -Pfile=src/path/to/file.tsx
# Run lint-fix on all files
../gradlew yarnLintFix
# Run type checking
yarn type-check
# Run tests
yarn test
# Run specific test file
yarn test path/to/file.test.tsx --run
Writing Tests - Best Practices & Common Pitfalls
Test Setup Essentials
Always use the existing test infrastructure:
- Use 
TestPageContainerfrom@utils/test-utils/TestPageContainer- it provides all necessary providers - Use 
MockedProviderfrom@apollo/client/testingfor GraphQL components - Use Vitest with React Testing Library