-
Notifications
You must be signed in to change notification settings - Fork 469
docs: add frontend developer documentation #6486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Zaimwa9
wants to merge
38
commits into
main
Choose a base branch
from
docs/backend-frontend-agents-context
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,689
−69
Open
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
ba3b42e
Claude context
kyle-ssg 9746d13
Claude context
kyle-ssg 5955f25
Claude context
kyle-ssg efedbdc
Add api-sync / optmimise contexts
kyle-ssg cae73d7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 23a6495
Add api-sync / optimise contexts
kyle-ssg af5bfda
Merge remote-tracking branch 'origin/chore/claude-context' into chore…
kyle-ssg ac641db
Update contexts
kyle-ssg 0c03b8f
Update contexts
kyle-ssg fb2df65
Update contexts
kyle-ssg b064e81
Update contexts
kyle-ssg 27019de
Update contexts
kyle-ssg 96c81d6
Update contexts
kyle-ssg 4a3bafa
Update contexts
kyle-ssg 4b846d9
Update contexts
kyle-ssg 6cbde85
Merge branch 'main' into chore/claude-context
kyle-ssg dd7b743
Update contexts
kyle-ssg df85873
Update claude contexts
kyle-ssg d4809c4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 885cfe0
Simplify contexts
kyle-ssg 91b542e
Merge remote-tracking branch 'origin/chore/claude-context' into chore…
kyle-ssg 7edc926
Merge branch 'main' into chore/claude-context
kyle-ssg 5b64f88
Revert makefile changes
kyle-ssg d9132b3
- Add AGENTS.md
khvn26 3d7a4aa
rename api/README.md
khvn26 6df6fc0
fix typo
khvn26 31e3c5e
fix path separators
khvn26 fb75a62
fix typo
khvn26 30a7158
clarify migrations squashing recommendation
khvn26 5feac3c
fix grammar
khvn26 453b867
update pull request template to include additional checklist items
khvn26 1fcdb88
Merge branch 'chore/claude-context' of github.com:Flagsmith/flagsmith…
Zaimwa9 9c4a74b
docs: split-heavy-context-and-created-agents
Zaimwa9 6c2fcaf
docs: basic-readme-for-frontend
Zaimwa9 ce3e9d4
docs: fixed-broken-link
Zaimwa9 845ad75
Remove mobile draft
kyle-ssg 750a2ad
feat: rebased
Zaimwa9 4213b50
Merge branch 'main' of github.com:Flagsmith/flagsmith into docs/backe…
Zaimwa9 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| description: Generate a new RTK Query API service | ||
| --- | ||
|
|
||
| <!-- TODO: Update /api-types-sync once OpenAPI schema is ready --> | ||
|
|
||
| Generate a new API service. Follow these steps: | ||
|
|
||
| 1. Go through the process mentioned in `.claude/context/api-integration.md` | ||
| 2. If I haven't specified, attempt to find where I'd want to create this component in the frontend | ||
|
|
||
| Context file: `.claude/context/api-integration.md` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| --- | ||
| description: Search the backend codebase for endpoint details | ||
| --- | ||
|
|
||
| Search the `../api` codebase for the requested endpoint. | ||
|
|
||
| Look for: | ||
| 1. Route definitions (URL path) | ||
| 2. HTTP method (GET, POST, PUT, DELETE) | ||
| 3. Request validation schema (request body/params types) | ||
| 4. Response structure (what data is returned) | ||
| 5. Authentication/authorization requirements | ||
|
|
||
| If the endpoint isn't found, check swagger docs: https://staging.flagsmith.com/api/v1/docs/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| description: Run type checking and linting on staged files | ||
| --- | ||
|
|
||
| Run TypeScript checking and linting on all currently staged files, similar to pre-commit hooks. Steps: | ||
| 1. Run `npm run check:staged` to typecheck and lint only staged files | ||
| 2. Report any type errors or linting issues found | ||
| 3. If errors exist, offer to fix them |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| --- | ||
| description: Run type checking and linting | ||
| --- | ||
|
|
||
| Run the following checks on the codebase: | ||
|
|
||
| 1. `npx lint-staged --allow-empty` - Fix linting issues on staged files only (same as git hook) | ||
|
|
||
| Report any errors found and offer to fix them. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| description: Load detailed context files for specific topics | ||
| --- | ||
|
|
||
| Available context files in `.claude/context/`: | ||
|
|
||
| 1. **api-integration.md** - API integration workflow, Redux setup, cross-platform patterns | ||
| 2. **architecture.md** - Environment config, tech stack, additional rules | ||
| 3. **feature-flags/** - Flagsmith feature flags (usage + MCP workflows) | ||
| 4. **patterns/** - Code patterns (API, mobile) | ||
|
|
||
| Which context would you like to explore? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| description: Create a feature flag | ||
| --- | ||
|
|
||
| 1. Create a feature flag using the context defined in `.claude/context/feature-flags/` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| --- | ||
| description: Create a new form using Yup + Formik pattern | ||
| --- | ||
|
|
||
| Create a form following the standard pattern: | ||
|
|
||
| 1. Use `useFormik` hook with `validationSchema` from Yup | ||
| 2. Always include `validateOnMount: true` | ||
| 3. Use `validateForm` utility from `project/utils/forms/validateForm` in submit handler | ||
| 4. Use `InputGroup` component with `touched` and `error` props | ||
| 5. For special inputs (date, phone, select), use `component` prop on InputGroup | ||
|
|
||
| Reference: `/examples/forms/ComprehensiveFormExample.tsx` | ||
|
|
||
| Context file: `.claude/context/forms.md` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # UI Patterns & Best Practices | ||
|
|
||
| ## Confirmation Dialogs | ||
|
|
||
| **NEVER use `window.confirm`** - Always use the `openConfirm` function from `components/base/Modal`. | ||
|
|
||
| ### Correct Usage | ||
|
|
||
| ```typescript | ||
| import { openConfirm } from 'components/base/Modal' | ||
|
|
||
| // Signature: openConfirm(title, body, onYes, onNo?, challenge?) | ||
| openConfirm( | ||
| 'Delete Partner', | ||
| 'Are you sure you want to delete this partner?', | ||
| async (closeModal) => { | ||
| const res = await deleteAction() | ||
| if (!res.error) { | ||
| toast(null, 'Partner deleted successfully') | ||
| closeModal() // Always call closeModal to dismiss the dialog | ||
| } | ||
| }, | ||
| ) | ||
| ``` | ||
|
|
||
| ### Parameters | ||
| - `title: string` - Dialog title | ||
| - `body: ReactNode` - Dialog content (can be JSX) | ||
| - `onYes: (closeModal: () => void) => void` - Callback when user confirms | ||
| - `onNo?: () => void` - Optional callback when user cancels | ||
| - `challenge?: string` - Optional challenge text user must type to confirm | ||
|
|
||
| ### Key Points | ||
| - The `onYes` callback receives a `closeModal` function | ||
| - Always call `closeModal()` when the action completes successfully | ||
| - Can be async - use `async (closeModal) => { ... }` | ||
|
|
||
| ## Backend Integration | ||
|
|
||
| ### Always Run API Types Sync Before API Work | ||
|
|
||
| When using `/api` to generate new API services, the command automatically runs `/api-types-sync` first to: | ||
| 1. Pull latest backend changes (`git pull` in `../api`) | ||
| 2. Sync frontend types with backend serializers | ||
| 3. Ensure types are up-to-date before generating new services | ||
|
|
||
| This prevents type mismatches and ensures consistency. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,220 @@ | ||
| # API Integration Guide | ||
|
|
||
| ## Overview | ||
|
|
||
| This project uses **RTK Query** (Redux Toolkit Query) for all API calls. The workflow is optimized for type safety and automatic sync with backend Django serializers. | ||
|
|
||
| **Finding Backend Endpoints**: See `.claude/context/backend-integration.md` for strategies to locate and understand backend API endpoints. | ||
|
|
||
| ## Quick Start: Adding a New Endpoint (Complete Example) | ||
|
|
||
| This example shows how to add a new endpoint for fetching company invoices (a real implementation from the codebase). | ||
|
|
||
| ### Step 1: Find Backend Endpoint | ||
|
|
||
| Use strategies from `backend-integration.md` to locate the endpoint. | ||
|
|
||
| **Backend endpoint found:** `GET /organisations/{organisation_id}/invoices` | ||
|
|
||
| ### Step 2: Add Request Type | ||
|
|
||
| **File:** `common/types/requests.ts` | ||
|
|
||
| ```typescript | ||
| export type Req = { | ||
| // ... existing types | ||
| getCompanyInvoices: { | ||
| organisation_id: string | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 3: Add RTK Query Endpoint | ||
|
|
||
| **File:** `common/services/useInvoice.ts` | ||
|
|
||
| ```typescript | ||
| export const invoiceService = service | ||
| .enhanceEndpoints({ addTagTypes: ['Invoice'] }) | ||
| .injectEndpoints({ | ||
| endpoints: (builder) => ({ | ||
| // Add new endpoint | ||
| getCompanyInvoices: builder.query< | ||
| Res['invoices'], | ||
| Req['getCompanyInvoices'] | ||
| >({ | ||
| providesTags: [{ id: 'LIST', type: 'Invoice' }], | ||
| query: (req) => ({ | ||
| url: `organisations/${organisation_id}/invoices`, | ||
| }), | ||
| transformResponse(res: InvoiceSummary[]) { | ||
| return res?.map((v) => ({ ...v, date: v.date * 1000 })) | ||
| }, | ||
| }), | ||
| }), | ||
| }) | ||
|
|
||
| export const { | ||
| useGetCompanyInvoicesQuery, // Export new hook | ||
| // END OF EXPORTS | ||
| } = invoiceService | ||
| ``` | ||
|
|
||
| ### Step 4: Use in Component | ||
|
|
||
| ```typescript | ||
| import { useGetCompanyInvoicesQuery } from 'common/services/useInvoice' | ||
|
|
||
| const MyComponent = () => { | ||
| const { subscriptionDetail } = useDefaultSubscription() | ||
| const companyId = subscriptionDetail?.company_id | ||
|
|
||
| const { data: invoices, error, isLoading } = useGetCompanyInvoicesQuery( | ||
| { organisation_id: `${companyId}` }, | ||
| { skip: !organisation_id } // Skip if no company ID | ||
| ) | ||
|
|
||
| if (isLoading) return <Loader /> | ||
| if (error) return <ErrorMessage>{error}</ErrorMessage> | ||
|
|
||
| return ( | ||
| <div> | ||
| {invoices?.map(inv => <div key={inv.id}>{inv.id}</div>)} | ||
| </div> | ||
| ) | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 5: Run Linter | ||
|
|
||
| ```bash | ||
| npx eslint --fix common/types/requests.ts common/services/useInvoice.ts | ||
| ``` | ||
|
|
||
| **Done!** The endpoint is now integrated and ready to use. | ||
|
|
||
| ## Manual Service Creation (Rare Cases) | ||
|
|
||
| If you need to manually create a service (follow template in `.claude/commands/api.md`): | ||
|
|
||
| 1. **Identify backend endpoint** | ||
| - Use `/backend <search-term>` to search backend codebase | ||
| - Check `../api/apps/*/serializers.py`, `../api/apps/*/views.py`, `apps/*/urls.py` | ||
| - Or swagger docs: https://api.flagsmith.com/api/v1/docs/ | ||
|
|
||
| 2. **Define types** in `common/types/` | ||
| - Response: `export type EntityName = { field: type }` in `responses.ts` | ||
| - Add to `Res` type: `entityName: EntityName` | ||
| - Request: `getEntityName: { param: type }` in `requests.ts` | ||
|
|
||
| 3. **Create service** `common/services/use{Entity}.ts` | ||
| - Use `builder.query` for GET, `builder.mutation` for POST/PUT/DELETE | ||
| - Configure cache tags: `providesTags`, `invalidatesTags` | ||
| - Export hooks: `useGetEntityQuery`, `useCreateEntityMutation` | ||
|
|
||
| 4. **Register in type map** `.claude/api-type-map.json` | ||
| - Add to `response_types` or `request_types` with full metadata | ||
| - Increment `_metadata.totalTypes` | ||
|
|
||
| 5. **Run linter** | ||
| ```bash | ||
| npx eslint --fix common/services/use*.ts common/types/*.ts | ||
| ``` | ||
|
|
||
| ### Backend → Frontend Type Mapping | ||
|
|
||
| | Django Type | TypeScript | | ||
| |------------|------------| | ||
| | `CharField` | `string` | | ||
| | `IntegerField` | `number` | | ||
| | `BooleanField` | `boolean` | | ||
| | `DateTimeField` | `string` (ISO) | | ||
| | `required=False` | `field?: type` | | ||
| | `many=True` | `Type[]` | | ||
| | Enum/Choices | `'A' \| 'B'` | | ||
|
|
||
| ### Example Service Structure | ||
|
|
||
| ```typescript | ||
| import { service } from 'common/service' | ||
| import { Req } from 'common/types/requests' | ||
| import { Res } from 'common/types/responses' | ||
|
|
||
| export const entityService = service | ||
| .enhanceEndpoints({ addTagTypes: ['Entity'] }) | ||
| .injectEndpoints({ | ||
| endpoints: (builder) => ({ | ||
| getEntity: builder.query<Res['entity'], Req['getEntity']>({ | ||
| providesTags: (res) => [{ id: res?.id, type: 'Entity' }], | ||
| query: (query) => ({ | ||
| url: `entities/${query.id}`, | ||
| }), | ||
| }), | ||
| updateEntity: builder.mutation<Res['entity'], Req['updateEntity']>({ | ||
| invalidatesTags: (res) => [ | ||
| { id: 'LIST', type: 'Entity' }, | ||
| { id: res?.id, type: 'Entity' }, | ||
| ], | ||
| query: (query) => ({ | ||
| body: query, | ||
| method: 'PUT', | ||
| url: `entities/${query.id}`, | ||
| }), | ||
| }), | ||
| // END OF ENDPOINTS | ||
| }), | ||
| }) | ||
|
|
||
| export const { | ||
| useGetEntityQuery, | ||
| useUpdateEntityMutation, | ||
| // END OF EXPORTS | ||
| } = entityService | ||
| ``` | ||
|
|
||
| See `common/services/useAuditLog.ts` for a complete example. | ||
|
|
||
| ## State Management | ||
|
|
||
| - **Redux Toolkit + RTK Query** for all API calls | ||
| - Store: `common/store.ts` with redux-persist | ||
| - Base service: `common/service.ts` | ||
| The `npx ssg` CLI requires interactive input that cannot be automated. Instead, **manually create RTK Query services** following the patterns in existing service files. | ||
| - **IMPORTANT**: When implementing API logic, prefer implementing it in the RTK Query service layer (using `transformResponse`, `transformErrorResponse`, etc.) rather than in components. This makes the logic reusable across the application. | ||
|
|
||
| ## Error Handling Patterns | ||
|
|
||
| ### RTK Query Mutations | ||
|
|
||
| ```typescript | ||
| const [createMail, { isLoading, error }] = useCreateMailMutation() | ||
|
|
||
| const handleSubmit = async () => { | ||
| try { | ||
| const result = await createThing(data).unwrap() | ||
| toast('Success!') | ||
| } catch (err) { | ||
| if ('status' in err) { | ||
| // FetchBaseQueryError - has status, data, error | ||
| const errMsg = 'error' in err ? err.error : JSON.stringify(err.data) | ||
| toast.error(errMsg) | ||
| } else { | ||
| // SerializedError - has message, code, name | ||
| toast(err.message || 'An error occurred', 'danger') | ||
| toast(err.message || 'An error occurred') | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### RTK Query Queries | ||
|
|
||
| ```typescript | ||
| const { data, error, isLoading, refetch } = useThing({ id: '123' }) | ||
|
|
||
| // Display error in UI, it won't render if error is undefined | ||
| return <ErrorMessage>{error}</ErrorMessage> | ||
|
|
||
| // Retry on error | ||
| const handleRetry = () => refetch() | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Architecture & Configuration | ||
|
|
||
| ## Environment Configuration | ||
|
|
||
| - Config files: `env/project_<ENV>.js` | ||
| - Available environments: `dev`, `prod`, `staging`, `local`, `selfhosted`, `e2e` | ||
| - Project config: `common/project.js` (imports from env files) | ||
| - Override: `ENV=local npm run dev` or `ENV=staging npm run dev` | ||
|
|
||
| ## Key Technologies | ||
|
|
||
| - React 16.14 + TypeScript + Bootstrap 5.2.2 | ||
| - Redux Toolkit + RTK Query (API state management) | ||
| - Flux stores (legacy state management) | ||
| - Webpack 5 + Express dev server | ||
| - Sentry (error tracking) | ||
| - Flagsmith (feature flags - this project IS Flagsmith, dogfooding its own platform) | ||
|
|
||
| ## Additional Rules | ||
|
|
||
| - **TypeScript/ESLint**: Build may ignore some errors, but always run linting on modified files | ||
| - **Web-specific code**: Goes in `/web/` directory (not `/common`) | ||
| - **Redux Persist**: Whitelist in `common/store.ts` | ||
| - **Imports**: Always use path aliases (`common/*`, `components/*`, `project/*`) - NO relative imports | ||
|
|
||
| ## Documentation | ||
|
|
||
| Check the main repository README and docs for additional information |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
worth waiting and having it complete