### Install Dependencies and Configure Environment Source: https://github.com/geobrowser/geogenesis/blob/master/CONTRIBUTING.md Installs project dependencies using Bun, navigates to the web application directory, and copies the environment example file to create a local configuration. ```bash bun install cd apps/web cp .env.example .env.local # fill in the .env.local file with the correct values ``` -------------------------------- ### Run Frontend Development Server Source: https://github.com/geobrowser/geogenesis/blob/master/CONTRIBUTING.md Navigates to the web application directory and starts the development server using Bun. ```bash cd apps/web bun dev ``` -------------------------------- ### Run Development Server Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/README.md Starts the development server for Geobrowser. Use this for active development and testing. ```sh # Run dev bun dev ``` -------------------------------- ### Example Action Data Encoding Source: https://github.com/geobrowser/geogenesis/blob/master/docs/brainstorms/2026-02-02-member-management-hooks-brainstorm.md Illustrates how to encode the data for a specific action, such as adding a member, using `abi.encodeCall` with the target function signature. ```solidity bytes data; // abi.encodeCall(IDAOSpace.addMember, (targetSpaceId)) ``` -------------------------------- ### TanStack DB RelationsCollection Setup Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/PROPOSAL-tanstack-db.md Sets up 'relationsCollection' using TanStack DB's queryCollectionOptions with 'on-demand' sync. It mirrors the valuesCollection setup but focuses on relation data, including schema, key extraction, and query function. ```typescript export const relationsCollection = createCollection( queryCollectionOptions({ id: 'relations', schema: relationSchema, getKey: relation => relation.id, syncMode: 'on-demand', queryKey: ['relations'], queryFn: async ctx => { const predicates = ctx.meta?.loadSubsetOptions; const where = tanstackPredicatesToWhereCondition(predicates); const filter = convertWhereConditionToEntityFilter(where); const entities = await getAllEntities({ filter }); return entities.flatMap(e => e.relations); }, }) ); ``` -------------------------------- ### TanStack DB QueryCollection Setup Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/PROPOSAL-tanstack-db.md Sets up 'valuesCollection' using TanStack DB's queryCollectionOptions with 'on-demand' sync. It includes schema, key extraction, query key, and a query function that translates TanStack predicates to API filters. ```typescript import { queryCollectionOptions } from '@tanstack/query-db-collection'; import { createCollection } from '@tanstack/react-db'; export const valuesCollection = createCollection( queryCollectionOptions({ id: 'values', schema: valueSchema, getKey: value => value.id, syncMode: 'on-demand', queryKey: ['values'], queryFn: async ctx => { // TanStack passes predicates from useLiveQuery const predicates = ctx.meta?.loadSubsetOptions; // Translate: TanStack predicates → WhereCondition → GraphQL const where = tanstackPredicatesToWhereCondition(predicates); const filter = convertWhereConditionToEntityFilter(where); const entities = await getAllEntities({ filter }); return entities.flatMap(e => e.values); }, onUpdate: async ({ transaction }) => { // Handle optimistic updates - called when value is mutated // Could be no-op if we batch publish separately }, }) ); ``` -------------------------------- ### useQueryEntities sortBy Example Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/AUDIT.md This snippet shows the sortBy configuration within the useQueryEntities hook. Note that the sortBy functionality is hardcoded but not fully implemented in the applySorting function. ```tsx .sortBy({ field: 'updatedAt', direction: 'desc' }) ``` -------------------------------- ### PostgreSQL Optimal Active Connections Formula Source: https://github.com/geobrowser/geogenesis/blob/master/docs/research/2026-02-04-topic-synthesis-postgres-connection-pooling.md This formula provides a starting point for determining the optimal number of active connections based on hardware factors. It's crucial to consider that 'effective_spindle_count' can vary based on cache hit rates. ```text Optimal active connections = (core_count * 2) + effective_spindle_count ``` -------------------------------- ### TanStack DB Collections Setup Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/PROPOSAL-tanstack-db.md Defines TanStack DB collections for 'values' and 'relations' using `localOnlyCollectionOptions`. Ensure `valueSchema` and `relationSchema` are defined elsewhere. ```typescript import { localOnlyCollectionOptions } from '@tanstack/db'; import { createCollection } from '@tanstack/react-db'; export const valuesCollection = createCollection( localOnlyCollectionOptions({ id: 'values', schema: valueSchema, getKey: value => value.id, }) ); export const relationsCollection = createCollection( localOnlyCollectionOptions({ id: 'relations', schema: relationSchema, getKey: relation => relation.id, }) ); ``` -------------------------------- ### Global Singleton Initialization Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/AUDIT.md Demonstrates the initialization of module-level singletons for the event stream, store, and sync engine. These singletons persist across route navigations. ```tsx export const stream = new GeoEventStream(); export const store = new GeoStore(stream); export const engine = new SyncEngine(stream, queryClient, store); ``` -------------------------------- ### Build Web Application Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/README.md Compiles the Geobrowser web application for deployment. This command generates optimized production assets. ```sh # Build web app bun build ``` -------------------------------- ### SpaceRegistry.enter() Function Signature Source: https://github.com/geobrowser/geogenesis/blob/master/docs/brainstorms/2026-02-02-member-management-hooks-brainstorm.md The `enter` function in `SpaceRegistry` is the entry point for all membership management actions. It accepts parameters for the caller's space, the target DAO space, the action type, topic, encoded data, and signature. ```solidity function enter( bytes16 _fromSpaceId, // Caller's personal space ID bytes16 _toSpaceId, // Target DAO space ID bytes32 _action, // PROPOSAL_CREATED bytes32 _topic, // bytes32(0) - fetch() returns proposalId bytes calldata _data, // Encoded proposal data bytes calldata _signature // Empty if caller owns fromSpace ) ``` -------------------------------- ### Verify Refactoring with Build Commands Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-refactor-flatten-v2-directory-structure-plan.md Run TypeScript compilation, tests, and build commands to ensure the refactoring changes have been applied correctly and the project remains functional. ```bash # TypeScript compilation pnpm tsc --noEmit # Run tests pnpm test # Build pnpm build ``` -------------------------------- ### Run Production Web App Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/README.md Builds and then runs the production version of the Geobrowser web application. This is typically used after the build step for deployment. ```sh # Run production version of web app bun build bun start ``` -------------------------------- ### Proposed File Structure Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-04-feat-voting-on-proposals-plan.md Illustrates the directory structure for new and modified files related to the voting feature. ```bash core/ ├── contracts/ │ └── voting.ts # NEW: Calldata encoding abstraction ├── hooks/ │ ├── use-vote.ts # MODIFY: Add validation, error handling │ └── use-proposal.ts # NEW: Merge server data with optimistic state ├── utils/ │ ├── contract-errors.ts # NEW: Contract error parsing │ └── transaction-errors.ts # NEW: Transaction classification └── state/ └── status-bar-store.tsx # MODIFY: Enhanced transaction states partials/ └── governance/ ├── proposal-vote-actions.tsx # NEW: Voting UI component └── governance-proposals-list.tsx # MODIFY: Add vote actions ``` -------------------------------- ### Data Encoding for PROPOSAL_CREATED Action Source: https://github.com/geobrowser/geogenesis/blob/master/docs/brainstorms/2026-02-02-member-management-hooks-brainstorm.md This structure shows how to encode proposal data for the `PROPOSAL_CREATED` action. It includes the proposal ID, voting mode, and an array of actions, where each action specifies the target address, value, and encoded data. ```solidity abi.encode( proposalId, // bytes16 - generated by hook votingMode, // VotingMode enum (Fast = 0, Slow = 1) actions // Action[] - array of {to, value, data} ) ``` -------------------------------- ### File Renaming and Relocation for v2 Flattening Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-refactor-flatten-v2-directory-structure-plan.md This snippet details the proposed file renames and relocations as part of flattening the 'io/v2/' directory. It outlines the target locations for files currently in 'io/v2/'. ```text io/v2/v2.schema.ts → io/schema.ts (rename legacy to substream-schema.ts first) OR → io/api-schema.ts (if keeping legacy schema.ts) io/v2/graphql.ts → io/graphql-client.ts (avoid conflict with subgraph/graphql.ts) io/v2/fragments.tsx → io/query-fragments.tsx (avoid conflict, clarify purpose) io/v2/queries.ts → io/queries.ts io/v2/converters.ts → io/converters.ts io/v2/converters.test.ts → io/converters.test.ts io/v2/decoders/ → io/decoders/ ``` -------------------------------- ### Abstract Contract Encoding Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-04-feat-voting-on-proposals-plan.md Create a domain service to abstract ABI encoding details from the voting hook. ```typescript // core/contracts/voting.ts import { MainVotingAbi, VoteOption } from '@geoprotocol/geo-sdk/abis' import { encodeFunctionData } from 'viem' export type VoteChoice = 'ACCEPT' | 'REJECT' export const VotingContract = { encodeVote(proposalId: string, choice: VoteChoice): `0x${string}` { return encodeFunctionData({ abi: MainVotingAbi, functionName: 'vote', args: [ BigInt(proposalId), choice === 'ACCEPT' ? VoteOption.Yes : VoteOption.No, true, // tryEarlyExecution ], }) }, encodeExecute(proposalId: string): `0x${string}` { return encodeFunctionData({ abi: MainVotingAbi, functionName: 'execute', args: [BigInt(proposalId)], }) }, } ``` -------------------------------- ### Import New Member Hooks Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-member-management-hooks-plan.md Replace existing member management hooks with new ones that support proposing member additions and removals. ```typescript // Remove: import { useAddMember } from '../../core/hooks/use-add-member' import { useRemoveMember } from '../../core/hooks/use-remove-member' // Add: import { useProposeAddMember } from '../../core/hooks/use-propose-add-member' import { useProposeRemoveMember } from '../../core/hooks/use-propose-remove-member' ``` -------------------------------- ### Import New Editor Hooks Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-member-management-hooks-plan.md Replace existing editor management hooks with new ones that support proposing editor additions and removals. ```typescript // Remove: import { useAddEditor } from '../../core/hooks/use-add-editor' import { useRemoveEditor } from '../../core/hooks/use-remove-editor' // Add: import { useProposeAddEditor } from '../../core/hooks/use-propose-add-editor' import { useProposeRemoveEditor } from '../../core/hooks/use-propose-remove-editor' ``` -------------------------------- ### Rename and Move Schema Files Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-refactor-flatten-v2-directory-structure-plan.md Execute git commands to rename the legacy schema file and move V2 schema-related files to their new locations. This includes renaming the main schema file and relocating its associated graphql, fragments, queries, converters, and decoders. ```bash # Create backup branch git checkout -b refactor/flatten-v2-backup # Rename legacy schema first git mv apps/web/core/io/schema.ts apps/web/core/io/substream-schema.ts # Move v2 files git mv apps/web/core/io/v2/v2.schema.ts apps/web/core/io/schema.ts git mv apps/web/core/io/v2/graphql.ts apps/web/core/io/graphql-client.ts git mv apps/web/core/io/v2/fragments.tsx apps/web/core/io/query-fragments.tsx git mv apps/web/core/io/v2/queries.ts apps/web/core/io/queries.ts git mv apps/web/core/io/v2/converters.ts apps/web/core/io/converters.ts git mv apps/web/core/io/v2/converters.test.ts apps/web/core/io/converters.test.ts git mv apps/web/core/io/v2/decoders apps/web/core/io/decoders # Remove empty v2 directory rmdir apps/web/core/io/v2 ``` -------------------------------- ### Audit io/schema.ts Usages Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-refactor-flatten-v2-directory-structure-plan.md Use grep to find all occurrences of 'from "~/core/io/schema"' in TypeScript and TSX files within the apps/web directory. ```bash # Check all usages grep -r "from '~/core/io/schema" apps/web --include="*.ts" --include="*.tsx" ``` -------------------------------- ### Update List Item Name and Description Edits Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-11-fix-data-block-cell-writes-plan.md Shows how to update `onChangeEntry` calls for name and description edits in list items, aligning with the new action types for SET_NAME, SET_VALUE, FIND_ENTITY, and CREATE_ENTITY. ```typescript // Name edits → { type: 'SET_NAME', name: value } // Description edit → { type: 'SET_VALUE', property: descriptionProperty, value } // FOC Find/Create → { type: 'FIND_ENTITY', entity } / { type: 'CREATE_ENTITY', name } ``` -------------------------------- ### Add keepPreviousData to useQuery for Schema Transitions Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-10-fix-new-entity-default-properties-plan.md By adding `placeholderData: keepPreviousData` to the `useQuery` options, this prevents the schema from briefly becoming undefined when the query key changes, such as during type additions or removals. This option is already imported but was previously unused. ```typescript const { data: schema } = useQuery({ enabled: types.length > 0, placeholderData: keepPreviousData, queryKey: ['entity-schema-for-merging', entityId, types], queryFn: async () => await getSchemaFromTypeIds(types.map((t) => t.id)), }) ``` -------------------------------- ### Current Reactivity with useSelector Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/AUDIT.md This snippet illustrates the current global reactivity model where any change to values triggers all useSelector subscribers. This can lead to numerous selector runs and potential re-renders even if the data hasn't changed significantly for a specific component. ```typescript const reactive = createAtom(() => ({ values: reactiveValues.get(), relations: reactiveRelations.get(), })); ``` -------------------------------- ### PgBouncer Connection Limits Configuration Source: https://github.com/geobrowser/geogenesis/blob/master/docs/research/2026-02-04-topic-synthesis-postgres-connection-pooling.md Defines the maximum number of client connections and server connection pools for PgBouncer. 'max_client_conn' limits incoming connections, while 'default_pool_size' sets server connections per user/database pair. 'max_db_connections' and 'max_user_connections' can be set to 0 for unlimited server connections per database or user, respectively. ```ini max_client_conn = 100 default_pool_size = 20 max_db_connections = 0 max_user_connections = 0 ``` -------------------------------- ### Proposal Created Action Constant Source: https://github.com/geobrowser/geogenesis/blob/master/docs/brainstorms/2026-02-02-member-management-hooks-brainstorm.md Defines the keccak256 hash for the `PROPOSAL_CREATED` action type. This constant is used in the `SpaceRegistry.enter()` function to identify the type of governance action being performed. ```typescript const PROPOSAL_CREATED = keccak256('GOVERNANCE.PROPOSAL_CREATED') // = 0x... (compute at implementation time) ``` -------------------------------- ### Sync Engine Integration with TanStack DB Collections Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/PROPOSAL-tanstack-db.md Populates TanStack DB collections ('valuesCollection', 'relationsCollection') from fetched entities. Local changes take precedence over synced data. ```typescript // SyncEngine populates collections after fetch private syncEntities(entities: Entity[]) { for (const entity of entities) { for (const value of entity.values) { const existing = valuesCollection.get(value.id) if (existing?.isLocal) continue // Local wins valuesCollection.insert(value) } for (const relation of entity.relations) { const existing = relationsCollection.get(relation.id) if (existing?.isLocal) continue relationsCollection.insert(relation) } } } ``` -------------------------------- ### Handle Indexer Sync Gap with Polling Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-04-feat-voting-on-proposals-plan.md Implement polling with staged optimistic updates to handle indexer sync gaps after transaction confirmation. ```typescript onSuccess: async ({ hash, choice }) => { // Keep showing "confirming" state while polling // Poll for indexer to catch up (with timeout) const synced = await pollForIndexerSync({ proposalId: onchainProposalId, expectedVote: choice, maxAttempts: 10, intervalMs: 2000, }); // Only invalidate after indexer has synced queryClient.invalidateQueries({ queryKey: ['proposal', onchainProposalId] }); queryClient.invalidateQueries({ queryKey: ['proposals', spaceId] }); }, ``` -------------------------------- ### Add w-full to Property Wrapper Div Source: https://github.com/geobrowser/geogenesis/blob/master/docs/solutions/handoffs/format-card-width-20260210.md Ensures each property item takes the full width of the properties list container. This change is applied to the root div of a property item. ```tsx
``` -------------------------------- ### Action Struct for Proposal Data Source: https://github.com/geobrowser/geogenesis/blob/master/docs/brainstorms/2026-02-02-member-management-hooks-brainstorm.md Defines the structure for an individual action within a proposal. It includes the target contract address, the value to be sent (typically 0 for member management), and the encoded function call data. ```solidity struct Action { address to; uint256 value; bytes data; } ``` -------------------------------- ### Default Sorting Implementation Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/AUDIT.md Shows the default case in a switch statement for sorting fields. Fields not explicitly handled, such as 'createdAt' and 'updatedAt', are assigned empty strings, rendering their sorting ineffective. ```tsx switch (field) { case 'id': ... case 'name': ... case 'description': ... default: valueA = ''; valueB = ''; } ``` -------------------------------- ### Update External Imports using find and sed Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-refactor-flatten-v2-directory-structure-plan.md Perform find-and-replace operations across the codebase to update external import paths. This targets imports from v2 types, v2 queries, v2 converters, and the legacy schema. ```bash # Update v2.types imports (94+ files) find apps/web -type f \( -name "*.ts" -o -name "*.tsx" \) -exec sed -i '' "s|from '~/core/v2.types'|from '~/core/types'|g" {} + # Update v2/queries imports (15 files) find apps/web -type f \( -name "*.ts" -o -name "*.tsx" \) -exec sed -i '' "s|from '~/core/io/v2/queries'|from '~/core/io/queries'|g" {} + # Update v2/converters imports (2 files) find apps/web -type f \( -name "*.ts" -o -name "*.tsx" \) -exec sed -i '' "s|from '~/core/io/v2/converters'|from '~/core/io/converters'|g" {} + # Update legacy schema imports (14 files) find apps/web -type f \( -name "*.ts" -o -name "*.tsx" \) -exec sed -i '' "s|from '~/core/io/schema'|from '~/core/io/substream-schema'|g" {} + ``` -------------------------------- ### Handle String Equality with StartsWith Source: https://github.com/geobrowser/geogenesis/blob/master/apps/web/core/sync/AUDIT.md Addresses a semantic bug where the 'equals' condition in string matching incorrectly uses 'startsWith', leading to false positives. This code snippet shows the implementation of the 'equals' check. ```tsx if (condition.equals !== undefined) { // @TODO For now we use startsWith as equals to match the previous behavior if (!compareOperators.string.startsWith(value, condition.equals)) { return false; } } ``` -------------------------------- ### Define Action Types and onChangeEntry Signature Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-11-fix-data-block-cell-writes-plan.md Defines the possible actions that can flow through `onChangeEntry` and the new signature for the `onChangeEntry` function. This replaces older action types and simplifies the function's parameters. ```typescript import { Property, Value } from '~/core/types' import { Mutator } from '~/core/sync/use-mutate' // Actions that flow through onChangeEntry — all of these can be the first // interaction with a placeholder row, triggering entity creation. // // Property cells on existing entities write directly via storage.* since // they never involve placeholders. export type Action = | { type: 'SET_VALUE'; property: Property; value: string } | { type: 'SET_NAME'; name: string } | { type: 'FIND_ENTITY' entity: { id: string name: string | null space?: string verified?: boolean } } | { type: 'CREATE_ENTITY'; name: string | null } export type onChangeEntryFn = ( entityId: string, spaceId: string, action: Action ) => void export type onLinkEntryFn = ( id: string, to: { id: string name: string | null space?: string verified?: boolean }, currentlyVerified?: boolean ) => void /** * Shared value write logic. Used by onChangeEntry (for placeholder rows) * and by ValueGroup/EditableValueGroup (for existing entities). */ export function writeValue( storage: Mutator, entityId: string, spaceId: string, property: Pick, value: string, existingValue: Value | null ) { if (existingValue) { storage.values.update(existingValue, (draft) => { draft.value = value }) } else { storage.values.set({ entity: { id: entityId, name: null }, property: { id: property.id, name: property.name, dataType: property.dataType, }, spaceId, value, }) } } ``` -------------------------------- ### Rename Core Types File Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-refactor-flatten-v2-directory-structure-plan.md This snippet shows the proposed renaming of the v2 types file to the main types file, indicating a merge with existing content. ```text core/v2.types.ts → core/types.ts ``` -------------------------------- ### Original Tab Component Structure Source: https://github.com/geobrowser/geogenesis/blob/master/docs/solutions/handoffs/tabs-underline-full-width-20250209.md Shows the original structure where the underline div was incorrectly positioned inside a w-max flex container, limiting its width. ```tsx
{tabs}
// Constrained by parent
``` -------------------------------- ### Merge Types Files Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-refactor-flatten-v2-directory-structure-plan.md Combine the contents of `types.ts` and `v2.types.ts` into a single `types.ts` file. This involves prepending the content of `types.ts` to `v2.types.ts` and then renaming the result. ```bash # Merge v2.types.ts into types.ts # v2.types.ts has domain types (Entity, Relation, Value, etc.) # types.ts has utility types (Profile, SpaceType, ReviewState, etc.) # No overlap - can be combined # Prepend types.ts content to v2.types.ts, then rename git mv apps/web/core/v2.types.ts apps/web/core/domain-types.ts.tmp cat apps/web/core/types.ts apps/web/core/domain-types.ts.tmp > apps/web/core/types.ts.new mv apps/web/core/types.ts.new apps/web/core/types.ts rm apps/web/core/domain-types.ts.tmp ``` -------------------------------- ### Extend DAOSpaceAbi with removeMember and removeEditor Source: https://github.com/geobrowser/geogenesis/blob/master/docs/plans/2026-02-02-member-management-hooks-plan.md Add function definitions for 'removeMember' and 'removeEditor' to the DAOSpaceAbi array in the space-registry.ts file. ```typescript { inputs: [{ internalType: 'bytes16', name: '_memberSpaceId', type: 'bytes16' }], name: 'removeMember', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [{ internalType: 'bytes16', name: '_editorSpaceId', type: 'bytes16' }], name: 'removeEditor', outputs: [], stateMutability: 'nonpayable', type: 'function', } ``` -------------------------------- ### Add Button Wrapper with Hover Styles Source: https://github.com/geobrowser/geogenesis/blob/master/docs/solutions/handoffs/space-dropdown-hover-20260209.md Wrap the Menu trigger in a button element with specific Tailwind CSS classes for rounded corners, padding, and hover background color to match the design system. This ensures the hover state is visible and consistent with other UI elements. ```tsx {isContextMenuOpen ? : } } ... /> ```