diff --git a/docs/src/contents/03.developer-guide/03.Modules.mdx b/docs/src/contents/03.developer-guide/03.Modules.mdx
new file mode 100644
index 000000000..ecf0c815a
--- /dev/null
+++ b/docs/src/contents/03.developer-guide/03.Modules.mdx
@@ -0,0 +1,262 @@
+import { Icon } from '@iconify/react';
+import CustomLink from '../../components/CustomLink';
+import Code from '../../components/Code';
+import Note from '../../components/Note';
+import Warning from '../../components/Warning';
+
+###### Modules
+
+# With Absolute Modularity in Mind
+
+Lifeforge is your canvas, and modules are the vibrant colors that bring your creations to life. With Lifeforge's modular architecture and your creativity, the possibilities are endless. Being a developer means you can craft your own modules to extend Lifeforge's capabilities. Whether you're looking to add new features, integrate with other tools, or customize the user experience, Lifeforge's modular design makes it easy to do so.
+
+---
+
+apps/ directory at the root of the repository. Each module is contained within its own subdirectory, following a consistent structure to ensure ease of development and maintenance.
+
+### client/lifeforge-ui is also provided in the packages/ directory, which you can use to maintain a consistent design language across your module.
+
+server/forgeController and forgeRouter, as well as the type-safe PocketBase wrapper PBService.
+
+locales/package.jsonForgeCLI tool, which provides a convenient command-line interface for managing LifeForge instances. The CLI includes a command to scaffold a new module with the necessary directory structure and boilerplate code.
+
+Simply run the following command in your terminal:
+
+
+{`bun run forge modules create`}
+
+
+Several prompts will guide you through the setup process, allowing you to customize the module's name, description, and other settings, which should look something like this:
+
+
+
+### Translation of Module Name and Description
+
+If you already have the OpenAI API key set in your API Key Vault, the CLI will automatically generate translation for your module name and description in multiple languages using OpenAI's GPT-4o-mini model. Otherwise, you can manually edit the localization files later.
+
+### Selecting Icon
+
+When prompted to select an icon for your module, you can choose from all the available icons in the Iconify library. The CLI will prompt for the icon sets and icon name separately using an autocomplete interface. However, it won't show a preview of the icon (it's already a proven concept, so it might be added in the future), so you might want to refer to the [Iconify website](https://icon-sets.iconify.design/) to find the icon you want beforehand.
+
+### Selecting Boilerplate
+
+You can choose from several boilerplate templates to kickstart your module development. Each boilerplate comes with pre-configured settings and sample code tailored for different use cases. You can also choose a blank template if you prefer to start from scratch.
+manifest.ts at the root of the client/ directory. This file serves as the entry point for the module's client application and defines the module's metadata and configuration.
+
+When creating a module using the ForgeCLI, a default manifest file will be generated for you with the basic structure and necessary fields. Here's an example of what the manifest file looks like:
+
+
+{`// apps/[module]/client/manifest.ts
+ import { lazy } from 'react'
+ import type { ModuleConfig } from 'shared'
+
+ export default {
+ name: 'My Module',
+ icon: 'tabler:cube',
+ routes: {
+ 'my-module': lazy(() => import('@'))
+ },
+ category: 'Utilities',
+ } satisfies ModuleConfig
+`}
+
+
+Shown below are the type definition for the ModuleConfig interface:
+
+{`export interface ModuleConfig {
+ // Basic module information
+ name: string
+ icon: string
+ // Global provider component for the module. If provided, it will wrap all routes in the module.
+ provider?:
+ | React.LazyExoticComponent
+category field in the manifest file. This categorization helps organize modules in the sidebar, making it easier for users to navigate and find the modules they need.
+
+All modules with the same category will be grouped together under a common heading in the sidebar and sorted alphabetically within that category. However, when it comes to the order of the categories themselves, there is a special file located at apps/cat.config.json that defines the order of the categories. This file exports an array of category names, which determines the order in which the categories are displayed in the sidebar. Categories that are not listed in this file will be placed at the end of the sidebar, sorted alphabetically.
+
+There are several special category names that are reserved for specific purposes. Their order is fixed and cannot be changed. Shown below is the order where your categories will be displayed in the sidebar:
+
+
+{`
+package.json file. This allows module developers to manage their own dependencies without affecting other modules or the main LifeForge codebase.
+
+When you install a module using the ForgeCLI, it will automatically install several commonly used dependencies that are more often than not required by most modules. These dependencies include:
+
+- **@iconify/react** – Icon library for rendering icons from Iconify
+- **@tanstack/react-query** – Data fetching and state management
+- **@uidotdev/usehooks** – Collection of useful React hooks
+- **clsx** – Utility for constructing className strings conditionally
+- **dayjs** – Lightweight date library for parsing, validating, and formatting dates
+- **lifeforge-ui** – LifeForge's internal UI component library (workspace dependency)
+- **react** – Core React library
+- **react-i18next** – Internationalization framework for React
+- **react-toastify** – Toast notification library
+- **shared** – Shared utilities and types across the monorepo (workspace dependency)
+- **vite** – Build tool and dev server
+- **zod** – TypeScript-first schema validation library
+
+These dependencies provide the foundational tools and libraries needed for building robust and feature-rich modules. However, module developers are free to add any additional dependencies they require for their specific module functionality.
+
+bun install in the respective module directory to ensure that the dependencies are installed in the desired module's context, otherwise they might end up being installed at the root level, causing potential waste of disk space and dependency mismanagement issues.
+ForgeCLI, it adds the module as a git submodule, pointing to the module's own Git repository. This way, you can easily update or switch to different versions of the module without interfering with other modules or the main codebase.
+
+By default, the ForgeCLI will install the latest stable release of the module from its Git repository. However, you can also specify a specific branch, tag, or commit hash to install a different version of the module if needed.
+
+You can verify that the module has been added as a git submodule by checking the .gitmodules file at the root of the main repository. This file contains information about all the submodules, including their paths and URLs. Or, you can run the following command to see the list of submodules:
+
+
+{`git submodule status`}
+
+
+The result will look something like this:
+
+
+
+ForgeCLI by providing the Git URL.
+
+ But don't worry, module publishing will be available soon!
+ForgeCLI to publish your module to your own GitHub repository. This allows other users to easily install your module in their own LifeForge instances. However, this requires you to have your GitHub CLI configured with the necessary permissions to create repositories on your behalf.
+
+To publish your module, simply run the following command in your terminal:
+
+
+{`bun run forge modules publish [module]`}
+
+
+Initially, your module will be created locally with a Git repository separated from the main LifeForge codebase. Once published, the module will be deleted from your local apps/ directory, and readded as a git submodule pointing to the newly created repository. This ensures that your module remains independent and can be updated separately from the main LifeForge codebase.
+
defineForm function and the FormModal compo
{`import { defineForm, FormModal } from 'lifeforge-ui'
-function MyForm({
-onClose
-}: {
-onClose: () => void;
-}) {
-const { formProps } = defineForm({}).build()
+ function MyForm({
+ onClose
+ }: {
+ onClose: () => void;
+ }) {
+ const { formProps } = defineForm({}).build()
return
@@ -569,7 +572,7 @@ Alternatively, you can use a Zod schema to define the validation rules for the f
In some cases, you may find yourself needing to explicitly manage the form state. This can be useful if you need fine-grained control over the form values or if you're working with complex form logic, for example populating a field with AI generated content.
-LifeForge uses zustand for form state management. The defineForm function exposes a formStateStore object which is a Zustand store that you can use to get and set the form values.
+LifeForge uses zustand for form state management. The defineForm function exposes a formStateStore object which is a Zustand store that you can use to get and set the form values. In addition, the onClick handler of the actionButtonProps also exposes the state getter and setter functions as its parameters.
{`
@@ -579,14 +582,15 @@ LifeForge uses zustand for form state management. The defineF
...,
actionButtonProps: {
...,
- onClick: () => {
- const { name } = formStateStore.getState()
+ onClick: (data, setData) => {
+ const { name } = data
const newName = await forgeAPI.myApp.coolStuff.generateCoolerName.mutate({
currentName: name
})
- formStateStore.setState(() => ({
+ setData((oldData) => ({
+ ...oldData,
name: newName
}))
}
@@ -594,6 +598,14 @@ LifeForge uses zustand for form state management. The defineF
}
}).build()
+ useEffect(() => {
+ const unsubscribe = formStateStore.subscribe((state) => {
+ console.log('Form state changed:', state)
+ })
+
+ return unsubscribe
+ }, [])
+
return
}
diff --git a/docs/src/contents/03.developer-guide/04.BuildingAPI.mdx b/docs/src/contents/03.developer-guide/06.BuildingAPI.mdx
similarity index 100%
rename from docs/src/contents/03.developer-guide/04.BuildingAPI.mdx
rename to docs/src/contents/03.developer-guide/06.BuildingAPI.mdx
diff --git a/docs/src/contents/03.developer-guide/05.DatabaseOperations.mdx b/docs/src/contents/03.developer-guide/07.DatabaseOperations.mdx
similarity index 100%
rename from docs/src/contents/03.developer-guide/05.DatabaseOperations.mdx
rename to docs/src/contents/03.developer-guide/07.DatabaseOperations.mdx
diff --git a/docs/src/contents/03.developer-guide/08.SyncingSchemas.mdx b/docs/src/contents/03.developer-guide/08.SyncingSchemas.mdx
new file mode 100644
index 000000000..662e10c90
--- /dev/null
+++ b/docs/src/contents/03.developer-guide/08.SyncingSchemas.mdx
@@ -0,0 +1,66 @@
+import Warning from '../../components/Warning'
+import Code from '../../components/Code'
+import Note from '../../components/Note'
+
+###### Syncing schemas
+
+# Making Sure Your Schemas Are Up-to-Date
+
+As a developer working with Lifeforge, it's crucial to ensure that your database schemas (located at apps/[module]/server/schemas.ts) are always in sync with your application's models. Lifeforge provides a straightforward way to synchronize your schemas using the ForgeCLI tool.
+
+---
+
+
+## Generating Schemas from Database
+
+When you make changes to your database structure, such as adding new tables or modifying existing ones, you do it through the PocketBase admin UI. To reflect these changes in your application's codebase, you need to generate the corresponding Zod schemas. You can do this by running the following command in your terminal:
+
+
+{`bun run forge db generate-schemas [module]`}
+
+
+Replace [module] with the name of the module for which you want to generate the schemas. If not specified, it will generate schemas for all modules.
+
+This command will connect to your PocketBase instance, retrieve the current database structure, and generate Zod schemas based on the collections and fields defined in your database. The generated schemas will be saved in the schema file of the respective module.
+
+The collection metadata will also be saved alongside with the zod schemas, which is used to generate migration scripts that sync the database structure with the codebase.
+
+
+If the schema file for a module does not exist yet, running this command will create a new schema file with the generated schemas.
+
+
+
+ ### Collection Naming Convention
+ When generating schemas from the database, make sure that your collection name follows the naming convention as follows:
+
+
+ {`module_name__collection_name`}
+
+
+ Note that everything should be in snake case. This convention is important because the ForgeCLI uses the module name prefix to determine which module the collection belongs to. If the naming convention is not followed, the collection will be ignored during the schema generation process.
+
+ For example, if you have a module named My Blog and a collection named post_entries, the collection should be named my_blog__post_entries in PocketBase for the ForgeCLI to recognize it correctly.
+
+ ### Do Not Modify Generated Schemas Manually
+ The Zod schemas generated by the ForgeCLI are automatically created based on the database structure. Therefore, it is strongly advised not to modify these generated schemas manually. Any manual changes made to the schemas may be overwritten the next time you run the schema generation command, leading to potential loss of your changes and inconsistencies between your codebase and database structure.
+
+
+
+
+## Applying Schemas to Database
+
+When you install or update a module, it is very likely that the module comes with its own set of database schemas that need to be applied to your PocketBase instance, or the module author has made changes to the existing schemas. To apply these schemas to your database, you can use the following command:
+
+
+{`bun run forge db generate-migrations [module]`}
+
+
+This command will read the collection metadata defined in the module's schema file and generate migration scripts to update your PocketBase database accordingly. If you specify a module name, it will only apply the migrations for that specific module; otherwise, it will apply migrations for all installed modules.
+
+Don't worry, this script will be run automatically whenever you install or update a module using the ForgeCLI, so you don't have to run it manually every time.
+
+
+ ### Backup Your Database
+ To prevent any potential data loss, it is highly recommended to back up your PocketBase database before running the migration command. LifeForge is utilizing the built-in migration system of PocketBase, which is (hopefully) generally safe, but it's always better to be cautious when making changes to your database structure.
+
+
\ No newline at end of file