Document Creator

A PhoenixKit module for document template management and PDF generation via Google Docs. Templates and documents live in Google Drive as Google Docs. Variables use {{ placeholder }} syntax and are substituted via the Google Docs API. PDF export uses the Google Drive export endpoint.

Features

Setup

1. Add the dependency

# In parent app's mix.exs
{:phoenix_kit_document_creator, path: "../phoenix_kit_document_creator"}

2. Install and migrate

mix deps.get
mix ecto.migrate   # Runs PhoenixKit's versioned migrations (V86 + V88)

3. Enable the module

Start your app, go to Admin > Modules, enable Document Creator.

4. Connect Google Docs

  1. Create a Google Cloud project with Docs API and Drive API enabled
  2. Create an OAuth 2.0 Client ID (Web application type)
  3. Go to Admin > Settings > Document Creator
  4. Enter the Client ID and Client Secret
  5. Click Connect and authorize the Google account
  6. Create /templates and /documents folders in the connected Google Drive

Prerequisites

Architecture

How it works

Template (Google Doc with {{ variables }})
    |  copy via Drive API
    v
Document (Google Doc copy)
    |  replaceAllText via Docs API
    v
Document (variables filled in)
    |  export via Drive API
    v
PDF
  1. Templates are Google Docs stored in a /templates folder in Drive. Variables like {{ client_name }} are auto-detected from the document text.
  2. Documents are created by copying a template via the Drive API, then substituting variable values using the Docs API replaceAllText endpoint.
  3. PDF export uses the Drive API file export endpoint — no local Chrome or binary dependencies needed.

Google Drive as source of truth

All document content lives in Google Drive. The Phoenix app serves as a coordinator:

Dependencies

Package Purpose
phoenix_kit Module behaviour, Settings API, admin layout, Routes
phoenix_live_view Admin pages
req HTTP client for Google Docs/Drive API

Admin Pages

The module registers 3 admin tabs plus a settings tab:

Page Path Description
Document Creator/admin/document-creator Landing page (redirects to first subtab)
Documents/admin/document-creator/documents List documents from Drive with thumbnails
Templates/admin/document-creator/templates List templates from Drive with thumbnails

Settings:

Page Path Description
Google OAuth/admin/settings/document-creator Connect/disconnect Google account, manage OAuth credentials

Database Schema

Three tables created by the PhoenixKit migration system (V86 for initial tables, V88 for Google Docs fields):

phoenix_kit_doc_templates

Column Type Description
uuid UUID (PK) Auto-generated
name string Template name
slug string URL-safe identifier (unique, auto-generated from name)
description text Template description
status string "published" or "trashed"
content_html text HTML content (cached from Google Doc)
content_css text CSS styles
variables jsonb Array of variable definitions
config jsonb Configuration (e.g., paper_size)
thumbnail text Base64 data URI for preview
google_doc_id string Google Doc ID for API operations

phoenix_kit_doc_documents

Column Type Description
uuid UUID (PK) Auto-generated
name string Document name
template_uuid UUID (FK) Template this was created from (optional)
content_html text HTML content (cached from Google Doc)
content_css text CSS styles
variable_values jsonb Map of variable values used during creation
config jsonb Configuration
thumbnail text Base64 data URI for preview
google_doc_id string Google Doc ID for API operations
created_by_uuid UUID Optional FK to users

phoenix_kit_doc_headers_footers

Column Type Description
uuid UUID (PK) Auto-generated
name string Display name
type string "header" or "footer" (discriminator)
html text HTML content
css text CSS styles
height string CSS height value (e.g., "25mm")
thumbnail text Base64 data URI for preview
google_doc_id string Google Doc ID for API operations
created_by_uuid UUID Optional FK to users

Context API

PhoenixKitDocumentCreator.Documents

All operations go through Google Drive — no local database CRUD for document content.

Templates

Documents.list_templates()                    # All templates from Drive /templates folder
Documents.create_template(name)               # Create blank Google Doc in /templates

Documents

Documents.list_documents()                    # All documents from Drive /documents folder
Documents.create_document(name)               # Create blank Google Doc in /documents

# Create from template with variable substitution
Documents.create_document_from_template(template_file_id, %{
  "client_name" => "Acme Corp",
  "date" => "2026-03-14"
}, name: "Acme Contract")
# Copies template, replaces {{ variables }}, returns {:ok, %{doc_id, url}}

Variables

Documents.detect_variables(file_id)           # {:ok, ["client_name", "date"]}

PDF Export

Documents.export_pdf(file_id)                 # {:ok, pdf_binary}

Folders

Documents.get_folder_ids()                    # %{templates_folder_id: ..., documents_folder_id: ...}
Documents.refresh_folders()                   # Re-discover from Drive
Documents.templates_folder_url()              # Google Drive URL for templates folder
Documents.documents_folder_url()              # Google Drive URL for documents folder

PhoenixKitDocumentCreator.GoogleDocsClient

Low-level Google API client used by the Documents context:

GoogleDocsClient.get_credentials()            # {:ok, creds} | {:error, :not_configured}
GoogleDocsClient.authorization_url(redirect)  # {:ok, url} | {:error, :client_id_not_configured}
GoogleDocsClient.exchange_code(code, uri)     # {:ok, creds} (exchanges OAuth code for tokens)
GoogleDocsClient.refresh_access_token()       # {:ok, new_token} (auto-refresh on 401)
GoogleDocsClient.connection_status()          # {:ok, %{email: ...}} | {:error, reason}

GoogleDocsClient.create_document(title, opts) # Create Google Doc in Drive
GoogleDocsClient.copy_file(id, name, opts)    # Copy file in Drive
GoogleDocsClient.replace_all_text(id, vars)   # Substitute {{ variables }} in a Doc
GoogleDocsClient.get_document_text(id)        # Extract plain text for variable detection
GoogleDocsClient.export_pdf(id)               # Export as PDF binary
GoogleDocsClient.fetch_thumbnail(id)          # Fetch thumbnail as base64 data URI

Variable System

Templates support {{ variable_name }} placeholders.

Auto-detection

Variables are extracted from Google Doc text content via regex:

PhoenixKitDocumentCreator.Variable.extract_from_html("<p>Dear {{ client_name }},</p>")
# => ["client_name"]

Type guessing

Variable types are guessed from names:

Name contains Guessed type
date:date
amount, price:currency
description, notes:multiline
anything else :text

Navigation (Paths Module)

All paths go through PhoenixKit.Utils.Routes.path/1 via the centralized Paths module:

alias PhoenixKitDocumentCreator.Paths

Paths.index()                  # /admin/document-creator
Paths.templates()              # /admin/document-creator/templates
Paths.documents()              # /admin/document-creator/documents
Paths.settings()               # /admin/settings/document-creator

PhoenixKit Module Integration

Behaviour callbacks

Callback Value
module_key"document_creator"
module_name"Document Creator"
version"0.1.2"
permission_metadata Key: "document_creator", icon: "hero-document-text"
children[]
admin_tabs 3 tabs (parent + documents + templates)
settings_tabs 1 tab (Google OAuth settings)

Permission

The module registers "document_creator" as a permission key. Owner and Admin roles get access automatically. Custom roles must be granted access via Admin > Roles.

Project Structure

lib/
  phoenix_kit_document_creator.ex              # Main module (behaviour callbacks, tab registration)
  phoenix_kit_document_creator/
    documents.ex                               # Context: list/create/export via Google Drive
    google_docs_client.ex                      # Google Docs + Drive API client with OAuth
    variable.ex                                # Extract {{ variables }} and guess types
    paths.ex                                   # Centralized URL path helpers
    schemas/
      document.ex                              # Document schema
      header_footer.ex                         # Header/footer schema (type discriminator)
      template.ex                              # Template schema (with slug auto-gen)
    web/
      documents_live.ex                        # Landing page (templates + documents tabs)
      google_oauth_settings_live.ex            # OAuth settings page
      components/
        create_document_modal.ex               # Multi-step creation modal

Development

Code quality

mix format
mix credo --strict
mix dialyzer

Running tests

# Unit tests only (no database needed)
mix test --exclude integration

# All tests (requires PostgreSQL)
createdb phoenix_kit_document_creator_test
mix test

License

MIT