← All Projects
A collection of my work and side projects
A Next.js application to create documents from pre-defined templates stored in PocketBase. Users can fill dynamic forms generated from a JSON schema, preview the resulting HTML (compiled with Handlebars), and generate or view cached PDFs. Images are uploaded and stored as assets in PocketBase. Robust client- and server-side validations are in place.
Table of Contents
- Overview
- Key Features
- Tech Stack
- Project Structure
- Core Architecture
- Data Model (PocketBase)
- API Routes
- Frontend Flows
- Template Schema Specification
- Validations
- PDF Generation and Caching
- Image Upload Flow
- Authentication and Routing
- Local Development
- How to Add a New Template
- Known Limitations and Future Improvements
- File Index
Overview
This project evolved from an initial GrapeJS + Appwrite editor concept into a streamlined system focused on:
- Using pre-defined templates stored in PocketBase
- Generating dynamic forms from a JSON schema
- Compiling templates with Handlebars (#if, #each) so optional sections render only when data exists
- Generating and caching PDFs on-demand using Puppeteer
- Strong validations for input types, email format, numerical ranges, and images
The current codebase is centered around PocketBase as backend and no longer uses Appwrite in runtime paths. The original README references Appwrite and GrapeJS; use this updated document going forward.
Key Features
- Template hub for each template ID with:
- List of generated documents
- Creation of new documents via a form
- Edit and Delete actions per document
- Click on a document card to open/view its PDF (generate if not cached)
- Dynamic form rendering from schema with:
- Support for a "fields" array schema format and a legacy flat-object schema
- Field types: text, textarea, number, date, select, image, array (repeating group)
- Client-side validations (required, type checking, pattern, min/max, minLength/maxLength, email, select options, array size)
- Real-time error messages and disabled submit button until valid
- Image uploads:
- Client validation of MIME and file size (configurable)
- Server validation to enforce image types and size limits
- Uploaded images stored in PocketBase assets
- PDF generation:
- A4 PDFs via Puppeteer with printBackground
- Caching in PocketBase assets per-document; re-use on subsequent view
- Conditional rendering (Handlebars):
- Optional fields wrapped in {{#if}} blocks
- Arrays rendered with {{#each}}; omitted when empty
Tech Stack
- Framework: Next.js 15 (App Router) + React 19
- Language: TypeScript
- Styling/UI: Tailwind CSS + shadcn/ui components
- Backend: PocketBase (self-hosted)
- PDF: Puppeteer
- Templates: Handlebars runtime on the client for preview