This repository is a full-stack, monorepo-based platform for building, managing, and interacting with dynamic forms. It uses a modern web stack to provide a robust, type-safe, and scalable architecture.
Root Forms allows users to:
- Create Forms: Build complex forms with multiple fields and custom themes.
- Collect Submissions: Share forms and gather user responses.
- Analyze Data: View and manage form submissions through a dedicated dashboard.
This project is structured as a Turborepo monorepo, separating concerns into individual applications and packages. This ensures modularity, reusability, and end-to-end type safety.
- Technology: Built with Next.js (App Router), React, and Tailwind CSS.
- Role: This is the main user interface. It contains the form builder, the dashboard for viewing responses, explore pages, and the publicly accessible pages for filling out forms.
- How it works: The frontend uses
@trpc/clientto make strictly-typed API calls to the backend. It also utilizes custom hooks to manage form state and UI components.
- Technology: Built with tRPC and Zod.
- Role: Serves as the bridge between the frontend and the business logic. It defines the API contracts (routes, inputs, and outputs).
- How it works:
- A frontend component requests data (e.g., "get form by ID").
- The request hits a tRPC route defined here.
- The route validates the incoming data using Zod schemas.
- If valid, it delegates the actual work to the Services Layer.
- Technology: Pure TypeScript.
- Role: Contains the core business rules of the application.
- How it works: Instead of putting database calls directly in the API layer, all core logic (e.g., validating a form submission, checking permissions, formatting data) lives here. The services use the Database package to read/write data.
- Technology: Drizzle ORM and PostgreSQL.
- Role: Manages all data persistence.
- How it works: Defines the database schema using Drizzle (Users, Forms, FormFields, FormSubmissions, FormThemes). It provides a typed client to the Services layer for executing SQL queries safely.
- A user clicks "Submit" on the Next.js
webapp. - The
webapp calls thesubmitFormtRPC mutation. - The
trpcpackage validates the payload against a Zod schema. - The
trpcpackage calls thecreateSubmissionfunction in theservicespackage. - The
servicespackage runs any necessary business logic, then uses thedatabasepackage's Drizzle client to insert the record into PostgreSQL. - The result is returned all the way back up the chain to the frontend, with complete type safety at every step.
This project uses pnpm for dependency management.
- Node.js (v18+)
- pnpm (v9+)
- Docker (for local PostgreSQL database)
-
Install dependencies:
pnpm install
-
Start the local database: This will spin up a PostgreSQL instance via Docker Compose.
pnpm db:up
-
Initialize the database: Generate the Drizzle ORM client and run migrations to create the tables.
pnpm db:generate pnpm db:migrate
(Optional) To visualize and manage your database data locally, you can use Drizzle Studio:
pnpm db:studio
-
Start the development server: Launch the Next.js frontend and tRPC backend in development mode.
pnpm dev
pnpm dev: Starts the development servers.pnpm build: Builds all apps and packages for production.pnpm lint: Runs ESLint checks across the repository.pnpm format: Formats code using Prettier.pnpm check-types: Runs TypeScript type checking.