AI-Driven Portal Setup & Customizations

Learn how to create your custom ReportBurster Portal with the help of AI.


Hey AI, Help Me ReportBurster Portal button

Accelerate your portal development using AI-powered tools and automation. This guide walks you through the full process of adding a new document/content type—from idea to automated publishing with ReportBurster—using real scripts, templates, and AI prompts.

Read here about Our AI Philosophy (how to build your own portal and use artificial intelligence to do it)

Quick Table of Contents

StepWhat You DoResult
1. Plan Your Document TypeDecide which document type you want to automate and publish to the portal (e.g., Statement)Clear requirements defined
2. Configure Your Content Type(s)Use the admin UI to define your document type and fieldsYour new content type is ready to manage your data
3. Create/Customize TemplatesGenerate or adapt PHP templates for single and list views (AI recommended)New file: single-(new-content-type).php and update to page-my-documents.php for secure, beautiful display
4. Automate PublishingGenerate a script to publish docs to your portal (AI recommended)New script file for ReportBurster to publish your docs for users
5. Test & IteratePublish some docs, log in as admin/user, verify everything worksPortal is ready for production
6. Reference & TipsSee sample scripts, templates, and AI prompts; get tips for best resultsFast-track your next setup

1. Plan Your Document Type

Think about the document type you need to automate and publish to the portal. Define its purpose, fields, and access rules to ensure smooth setup.

Note:
ReportBurster Portal comes bundled with three sample content types: Paystub, Payslip, and Invoice.
In this guide, you will configure a new custom content type called Statement.
Even if screenshots show Paystub, Payslip, or Invoice, always think in analogy for your own Statement type.

Portal templates in file explorer Caption: Example bundled templates for Paystub, Payslip, and Invoice.

You can use these bundled examples as guides for your own custom type.

To set up a new custom content type, you’ll update two existing scripts and create one new file:

  1. Create single-(new-content-type).php — displays individual documents to users.
  2. Update page-my-documents.php — shows the list of documents for each user (their account page).
  3. Update endExtractDocument.groovy — uploads your document data to ReportBurster2Portal.

Good news:
You don’t need to write these scripts yourself (unless you want to).
AI will generate the code for you, so you can focus on building your dream portal.

Hey AI, Help Me ReportBurster Portal button

2. Configure Your Content Type in Portal Admin UI

To add a new document type (e.g., Statement), use the portal admin UI.

AI is not needed here—simply configure your content type and fields as you need.

Why this step?
Every document type (like Statement, Payslip, Invoice) must be defined as a Pods "Custom Post Type" with the fields you want. This is the foundation for all portal features and automation.

How to do it:

  • Go to Pods Admin in your portal admin dashboard.
  • Click Add New to create a new Pod.
  • Choose Custom Post Type and fill in the name (e.g., "Statement").
  • Add all the fields you need (e.g., account holder, period, opening/closing balance).
  • Save your Pod.

Portal admin UI showing content type fields Caption: Example fields for Paystub. For Statement, define your own fields.

You can configure multiple document types—there is no limit.

Once you save, your new content type is instantly available in the portal and can be used in all further steps.
Create one or two sample records for testing the full flow end to end.

Portal admin create few 'Paystubs' Caption: Creating sample records for testing.

3. Create or Customize Templates

Now you need to control how your documents are displayed to users.
This is where AI can help you the most — by generating or adapting existing PHP templates for your new content type.

a. Single Document View

Portal templates in file explorer Caption: Example template files for single document view.

Copy single-paystub.php to single-statement.php.

Adjust the new template file to display your Statement fields and enforce access control.

Tip:
You don't have to write the PHP code yourself—AI can generate the script for you by adapting the existing example.

Hey AI, Help Me ReportBurster Portal button

ReportBurster Portal AI Prompt to generate the single template for custom type

Replace the marked areas in the AI prompt with your Statement content type definition and the full content of the example script (single-paystub.php).

Give the prompt to your preferred AI chat vendor and paste the returned code into your new single-statement.php file.

When you view a single Statement document, you'll see your custom layout (not the sample Paystub layout).

ReportBurster Portal view single document Caption: Example single document view. Your Statement will have its own layout.

b. List View (My Documents)

Portal user account page template in file explorer Caption: Example template for listing documents.

For the list view, modify the existing page-my-documents.php to list your Statement documents for the logged-in user.

ReportBurster Portal AI Prompt to generate the list template for custom type

Provide your Statement content type definition and the full code of the example script (page-my-documents-paystub.php) to the AI.

Paste the returned code into your updated page-my-documents.php file.

When you visit /my-documents, you'll see your custom Statement list layout.

ReportBurster Portal view list of documents in the my-documents account page Caption: Example list view. Your Statement will have its own layout.

4. Automate Statements Publishing with ReportBurster

Generate a Groovy script to publish documents to the portal via the API.

  • What the script must do:
    1. Check if the target portal user exists (by username/email); create if missing.
    2. Prepare document data for your content type.
    3. Publish the document via REST API (with authentication).

ReportBurster Portal AI Prompt to generate the script to publish documents on the portal

Provide your Statement content type definition and the full code of the example script (curl_paystub2portal.groovy) to the AI.

Paste the returned code into your scripts/burst/endExtractDocument.groovy file.

Tip:
Guard your code with:

if (ctx.settings.getTemplateName().toLowerCase().indexOf("statements2portal") != -1) {
  // AI-generated code here
}

so it only runs for Statement documents.

ReportBurster Portal generate Groovy publishing script using AI Caption: Example publishing script location.

Now, your Statement documents will be uploaded to ReportBurster2Portal automatically.

ReportBurster Portal StateMents2Portal execution Caption: Example execution for Statement documents.

ReportBurster works with any reporting or business software, including Crystal Reports, SAP, Oracle, Microsoft Dynamics, and more.

You can generate reports and upload to ReportBurster2Portal from any datasource.

5. Test and Iterate

  • Log in as admin and as a regular user to verify:
    • Documents appear in the dashboard/list view.
    • Access controls work as expected.
    • Single document view displays all fields correctly.
    • Automated publishing works and users are created as needed.

6. Reference & Tips for Using AI Effectively

Reference Scripts

Single document template:

single-paystub.php

<?php
/**
 * Generic secure single document template (works also for invoices etc.)
 *
 * Plain PHP (WordPress, Pods Framework, Tailwind CSS)
 *
 * Features:
 *  - Requires login.
 *  - Ownership via Pods User Relationship field: associated_user (if present).
 *
 * OPTIONAL Pods fields you may add (all boolean/relationships can be left empty):
 *  - allow_public_view     (Boolean)            If true: anyone with URL can view (no auth required).
 *  - associated_user       (User Relationship)  Exact WP User owner.
 *  - associated_groups      (Pick / Multi-Select) One or more WP group slugs allowed (e.g. it, hr).
 *  - associated_roles       (Pick / Multi-Select) One or more WP role slugs allowed (e.g. employee, customer).
 *
 * Logic (in order):
 *  1. If allow_public_view = true => bypass all other checks.
 *  2. Otherwise user must be logged in.
 *  3. If associated_user set => only that user (or admin) allowed.
 *  4. Else if associated_groups set => user must be in at least one matching group.
 *  5. Else if associated_roles set => user must have at least one matching role.
 *  6. Else fallback: require logged-in user (already enforced).
 *
 * You can reuse this file for other doc types by copying & renaming to single-invoice.php etc.
 */
if ( ! defined('ABSPATH') ) { exit; }
 
$pod = function_exists('pods') ? pods( get_post_type(), get_the_ID() ) : null;
if ( ! $pod ) {
    wp_die('Document data unavailable.');
}
 
$doc_type = get_post_type();
 
// --- 1. Public flag (uncomment after creating the field) ---
$allow_public_view = false;
/*
$allow_public_view = (bool) $pod->field('allow_public_view');
*/
 
// --- 2. Require login unless public ---
if ( ! $allow_public_view && ! is_user_logged_in() ) {
    auth_redirect(); // redirects & exits
    exit;
}
 
$current_user = wp_get_current_user();
$is_admin     = current_user_can('administrator');
 
// Collect intended access controls (may be empty if fields not defined)
$associated_user_id  = 0;
/*
$associated_user_id = (int) $pod->field('associated_user.ID');
*/
$associated_groups_ids = [];
/*
$associated_groups_ids = (array) $pod->field('associated_groups'); // adjust depending on Pods storage
*/
$associated_roles = [];
/*
$raw_roles = $pod->field('associated_roles');
$associated_roles = is_array($raw_roles) ? $raw_roles : ( $raw_roles ? [ $raw_roles ] : [] );
*/
 
// --- 3–5. Conditional enforcement (skip if public or admin) ---
if ( ! $allow_public_view && ! $is_admin ) {
 
    // 3. Exact user ownership
    if ( $associated_user_id ) {
        if ( get_current_user_id() !== $associated_user_id ) {
            wp_die('Not authorized (owner mismatch).');
        }
    }
    // 4. Group membership (placeholder – implement your own check)
    elseif ( $associated_groups_ids ) {
        /*
        // Example placeholder:
        $user_group_ids = []; // TODO: fetch groups for current user.
        if ( ! array_intersect( $associated_groups_ids, $user_group_ids ) ) {
            wp_die('Not authorized (group mismatch).');
        }
        */
    }
    // 5. Role-based access
    elseif ( $associated_roles ) {
        $user_roles = (array) $current_user->roles;
        if ( ! array_intersect( $associated_roles, $user_roles ) ) {
            wp_die('Not authorized (role mismatch).');
        }
    }
    // 6. Else: already logged in so allowed.
}
 
// ---------------- DATA FIELDS (only those that currently exist) ----------------
$employee    = esc_html( (string) $pod->display('employee') );
$period      = esc_html( (string) $pod->display('period') );
$grossAmount = number_format( (float) $pod->field('gross_amount'), 2 );
$netAmount   = number_format( (float) $pod->field('net_amount'), 2 );
 
// Load theme header (includes Tailwind and other assets)
get_header();
?>
 
<div class="max-w-xl mx-auto bg-white font-sans text-gray-900 p-6">
  <h1 class="text-2xl font-bold mb-2"><?php echo esc_html( get_the_title() ); ?></h1>
  <?php if ( $allow_public_view ): ?>
    <div class="text-xs text-gray-500 mb-4">Public document (no login required).</div>
  <?php endif; ?>
  <table class="w-full border border-gray-300 rounded-lg mt-6">
    <tbody>
      <tr class="border-b border-gray-200">
        <td class="py-2 px-4 font-medium">Employee</td>
        <td class="py-2 px-4"><?php echo $employee; ?></td>
      </tr>
      <tr class="border-b border-gray-200">
        <td class="py-2 px-4 font-medium">Period</td>
        <td class="py-2 px-4"><?php echo $period; ?></td>
      </tr>
      <tr class="border-b border-gray-200">
        <td class="py-2 px-4 font-medium">Gross Amount</td>
        <td class="py-2 px-4 text-right">$<?php echo $grossAmount; ?></td>
      </tr>
      <tr>
        <td class="py-2 px-4 font-medium">Net Amount</td>
        <td class="py-2 px-4 text-right">$<?php echo $netAmount; ?></td>
      </tr>
    </tbody>
  </table>
 
  <div class="mt-8 font-bold text-right bg-gray-100 p-4 rounded-lg text-lg">
    Net Pay: $<?php echo $netAmount; ?>
  </div>
 
  <div class="mt-10 flex justify-center gap-4 print:hidden">
    <?php
      $account_page_id = (int) get_option('reportburster_account_page_id');
      $back_url = $account_page_id
        ? get_permalink($account_page_id)
        : ( get_permalink( get_page_by_path('my-documents') ) ?: home_url() );
    ?>
    <a href="<?php echo esc_url( $back_url ); ?>"
       class="inline-block px-5 py-2 rounded bg-green-600 text-white hover:bg-green-700 transition">
      Back to Documents
    </a>
    <a class="inline-block px-5 py-2 rounded bg-blue-600 text-white hover:bg-blue-700 transition"
       href="javascript:window.print();">
      Print
    </a>
  </div>
</div>
 
<?php
// Load theme footer (includes scripts and closes HTML)
get_footer();
?>

List view template:

page-my-documents-paystubs.php

<?php
/**
 * My Documents (Paystubs list)
 * Plain PHP (WordPress, Pods Framework, Tailwind CSS)
 * Features:
 *  - Requires login.
 *  - Lists paystubs user may view.
 *  - Ownership via Pods User Relationship field: associated_user (if present).
 *  - Pagination (?page=N) & search (?q=term) on title or period.
 *  - Graceful when ownership field not yet defined.
 */
 
if ( ! defined('ABSPATH') ) { exit; }
if ( ! is_user_logged_in() ) { auth_redirect(); exit; }
 
$current_user     = wp_get_current_user();
$current_user_id  = (int) $current_user->ID;
$user_roles       = (array) $current_user->roles;
$is_admin         = current_user_can('administrator');
$is_employee      = in_array('employee', $user_roles, true);
 
$post_type        = 'paystub';
$ownership_field  = 'associated_user'; // Pods User Relationship field name
$per_page         = 15;
$page_param       = 'page';
$search_param     = 'q';
 
$paged        = max( 1, (int) ( $_GET[$page_param] ?? 1 ) );
$search_term  = isset($_GET[$search_param]) ? sanitize_text_field( wp_unslash( $_GET[$search_param] ) ) : '';
$offset       = ( $paged - 1 ) * $per_page;
 
$paystubs_rows   = [];
$paystubs_found  = false;
$total_found     = 0;
$total_pages     = 1;
$filtered_notice = '';
 
/**
 * Detect ownership field existence via Pods schema (not meta scan).
 */
$ownership_field_exists = false;
if ( function_exists('pods_api') ) {
    $schema = pods_api()->load_pod( [ 'name' => $post_type ] );
    if ( isset( $schema['fields'][ $ownership_field ] ) ) {
        $ownership_field_exists = true;
    }
}
 
/**
 * Query only if Pods active and user role allowed.
 */
if ( function_exists('pods') && ( $is_employee || $is_admin ) ) {
 
    $where = [];
 
    if ( $ownership_field_exists ) {
        if ( ! $is_admin ) {
            $where[] = "{$ownership_field}.ID = {$current_user_id}";
            $filtered_notice = '(Filtered to your documents)';
        } else {
            $filtered_notice = '(Admin – unfiltered)';
        }
    } else {
        if ( ! $is_admin ) {
            // Hide list from non-admins until ownership field defined
            $where[] = "ID = 0";
            $filtered_notice = '(Ownership field missing)';
        } else {
            $filtered_notice = '(Admin – ownership field missing, list unfiltered)';
        }
    }
 
    if ( $search_term !== '' ) {
        $like   = '%' . esc_sql( $search_term ) . '%';
        $where[] = "( post_title LIKE '{$like}' OR period LIKE '{$like}' )";
    }
 
    $params = [
        'limit'   => $per_page,
        'offset'  => $offset,
        'orderby' => 'post_date DESC',
    ];
    if ( $where ) {
        $params['where'] = implode( ' AND ', $where );
    }
 
    $pod = pods( $post_type, $params );
 
    if ( $pod ) {
        $total_found    = (int) $pod->total();
        $paystubs_found = $total_found > 0;
        $total_pages    = max( 1, (int) ceil( $total_found / $per_page ) );
 
        if ( $paystubs_found ) {
            while ( $pod->fetch() ) {
                $pid    = (int) $pod->id();
                $title  = get_the_title( $pid );
                $period = (string) $pod->display( 'period' );
                $grossV = (float) $pod->field( 'gross_amount' );
                $netV   = (float) $pod->field( 'net_amount' );
 
                $paystubs_rows[] = [
                    'title'  => esc_html( $title ),
                    'period' => esc_html( $period ),
                    'gross'  => $grossV ? '$' . number_format( $grossV, 2 ) : '',
                    'net'    => $netV   ? '$' . number_format( $netV, 2 )   : '',
                    'date'   => esc_html( get_the_date( 'Y-m-d', $pid ) ),
                    'link'   => esc_url( get_permalink( $pid ) ),
                ];
            }
        }
    }
}
 
/**
 * Simple pagination
 */
function my_docs_paginate( int $current, int $total, string $param = 'page' ): void {
    if ( $total < 2 ) return;
    echo '<nav class="flex justify-center mt-4 space-x-2 text-sm">';
    for ( $i = 1; $i <= $total; $i++ ) {
        $url = esc_url( add_query_arg( $param, $i ) );
        if ( $i === $current ) {
            echo '<span class="px-3 py-1 rounded bg-blue-600 text-white font-semibold">'.$i.'</span>';
        } else {
            echo '<a href="'.$url.'" class="px-3 py-1 rounded bg-gray-100 hover:bg-blue-100 text-blue-700">'.$i.'</a>';
        }
    }
    echo '</nav>';
}
 
// Load theme header (includes Tailwind and other assets)
get_header();
?>
 
<div class="max-w-3xl mx-auto py-8">
  <div class="flex justify-between items-center mb-6">
    <div class="text-sm text-gray-700">
      Logged in as <strong><?php echo esc_html( $current_user->display_name ); ?></strong>
    </div>
    <a class="text-red-600 hover:underline text-sm" href="<?php echo esc_url( wp_logout_url( home_url() ) ); ?>">Logout</a>
  </div>
 
  <h1 class="text-2xl font-bold mb-2">My Documents</h1>
  <p class="text-sm text-gray-600 mb-4">
    Paystubs you are authorized to view.
    <?php if ( $filtered_notice ) : ?>
      <span class="inline-block bg-blue-100 text-blue-800 px-2 py-0.5 rounded ml-2 text-xs"><?php echo esc_html( $filtered_notice ); ?></span>
    <?php endif; ?>
    <?php if ( $search_term !== '' ) : ?>
      <span class="inline-block bg-yellow-100 text-yellow-800 px-2 py-0.5 rounded ml-2 text-xs">Search: “<?php echo esc_html( $search_term ); ?></span>
    <?php endif; ?>
  </p>
 
  <div class="bg-white border border-gray-200 rounded-lg shadow-sm p-6">
    <div class="flex items-center justify-between mb-4">
      <h2 class="text-lg font-semibold mb-0">Paystubs
        <?php if ( $paystubs_found ): ?>
          <span class="ml-2 text-xs text-gray-500">(<?php echo (int) $total_found; ?> total)</span>
        <?php endif; ?>
      </h2>
      <form method="get" class="flex gap-2 items-center">
        <input
          type="text"
          name="<?php echo esc_attr( $search_param ); ?>"
          value="<?php echo esc_attr( $search_term ); ?>"
          placeholder="Search title or period..."
          class="border border-gray-300 rounded px-3 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-200"
        />
        <button type="submit" class="px-3 py-1 rounded bg-blue-600 text-white text-sm hover:bg-blue-700">Search</button>
        <?php if ( $search_term !== '' ): ?>
          <a href="<?php echo esc_url( remove_query_arg( $search_param ) ); ?>" class="ml-2 text-blue-600 hover:underline text-xs">Reset</a>
        <?php endif; ?>
      </form>
    </div>
 
    <?php if ( $paystubs_found ): ?>
      <div class="overflow-x-auto">
        <table class="min-w-full border border-gray-200 rounded-lg">
          <thead>
            <tr class="bg-gray-50">
              <th class="px-4 py-2 text-left text-xs font-semibold text-gray-700">Title</th>
              <th class="px-4 py-2 text-left text-xs font-semibold text-gray-700">Period</th>
              <th class="px-4 py-2 text-right text-xs font-semibold text-gray-700">Gross</th>
              <th class="px-4 py-2 text-right text-xs font-semibold text-gray-700">Net</th>
              <th class="px-4 py-2 text-left text-xs font-semibold text-gray-700">Date</th>
              <th class="px-4 py-2 text-center text-xs font-semibold text-gray-700" style="width:60px;">View</th>
            </tr>
          </thead>
          <tbody>
          <?php foreach ( $paystubs_rows as $row ): ?>
            <tr class="border-b last:border-b-0 hover:bg-gray-50">
              <td class="px-4 py-2"><?php echo $row['title']; ?></td>
              <td class="px-4 py-2"><?php echo $row['period']; ?></td>
              <td class="px-4 py-2 text-right"><?php echo $row['gross']; ?></td>
              <td class="px-4 py-2 text-right"><?php echo $row['net']; ?></td>
              <td class="px-4 py-2"><?php echo $row['date']; ?></td>
              <td class="px-4 py-2 text-center">
                <a href="<?php echo $row['link']; ?>" class="text-blue-600 hover:underline">View</a>
              </td>
            </tr>
          <?php endforeach; ?>
          </tbody>
        </table>
      </div>
      <?php my_docs_paginate( $paged, $total_pages, $page_param ); ?>
    <?php else: ?>
      <div class="py-6 text-center text-gray-500 italic">
        <?php if ( $search_term !== '' ): ?>
          No paystubs match “<?php echo esc_html( $search_term ); ?>”.
        <?php elseif ( ! $is_employee && ! $is_admin ): ?>
          No paystubs available for your role.
        <?php else: ?>
          No paystubs found.
        <?php endif; ?>
      </div>
    <?php endif; ?>
  </div>
</div>
 
<?php
// Load theme footer (includes scripts and closes HTML)
get_footer();
?>

Publishing script:

curl_paystub2portal.groovy

/*
 * Groovy Script for ReportBurster: Publish Paystub to WordPress Portal
 *
 * This script creates a new 'paystub' post in WordPress via REST API,
 * checking or creating the associated user as needed.
 *
 * Assumptions:
 * - Field values from user variables: var0=employee, var1=period, var2=gross_amount, var3=net_amount, var4=associated_user
 * - Authentication via Basic Auth (username:password).
 *
 * Inputs (replace placeholders):
 * - API_ENDPOINT: e.g., 'http://localhost:8080/wp-json/wp/v2/paystub'
 * - AUTH_METHOD: e.g., 'admin:password' for Basic Auth
 *
 * Reference: Adapted from curl_sftp.groovy sample.
 */
 
import groovy.ant.AntBuilder
import com.sourcekraft.documentburster.variables.Variables
 
// Inputs
def apiEndpoint = '[PASTE_API_ENDPOINT_HERE]'
def authMethod = '[API_KEY_OR_METHOD]'
 
// Burst context
def token = ctx.token
 
// Extract field values from user variables
def employee = ctx.variables.getUserVariables(ctx.token).get("var0")
def period = ctx.variables.getUserVariables(ctx.token).get("var1")
def grossAmount = ctx.variables.getUserVariables(ctx.token).get("var2").toFloat()
def netAmount = ctx.variables.getUserVariables(ctx.token).get("var3").toFloat()
def associatedUser = ctx.variables.getUserVariables(ctx.token).get("var4")
 
def ant = new AntBuilder()
 
// Step 1: Check/Create User
log.info("Step 1: Checking/Creating WordPress User")
def userCheckEndpoint = 'http://localhost:8080/wp-json/wp/v2/users'
def userEmail = associatedUser + '@example.com'
def userExists = false
 
def checkUserCmd = "-u ${authMethod} -X GET \"${userCheckEndpoint}?search=${associatedUser}\""
log.info("Checking user: curl.exe ${checkUserCmd}")
ant.exec(
    append: true,
    failonerror: false,
    output: "logs/user_check.log",
    executable: 'tools/curl/win/curl.exe'
) {
    arg(line: checkUserCmd)
}
def userCheckLog = new File("logs/user_check.log").text
if (userCheckLog.contains('"id"')) {
    userExists = true
    log.info("User exists.")
} else {
    def createUserData = "{\"username\":\"${associatedUser}\", \"email\":\"${userEmail}\", \"password\":\"defaultpass123\", \"roles\":[\"employee\"]}"
    def createUserCmd = "-u ${authMethod} -X POST -H \"Content-Type: application/json\" -d \"${createUserData}\" \"${userCheckEndpoint}\""
    log.info("Creating user: curl.exe ${createUserCmd}")
    ant.exec(
        append: true,
        failonerror: true,
        output: "logs/user_create.log",
        executable: 'tools/curl/win/curl.exe'
    ) {
        arg(line: createUserCmd)
    }
    log.info("User created.")
}
 
// Step 2: Prepare and Publish Post
log.info("Step 2: Preparing and Publishing Post")
def postData = [
    title: "${employee} - ${period}",
    status: 'publish',
    meta: [
        employee: employee,
        period: period,
        gross_amount: grossAmount,
        net_amount: netAmount,
        associated_user: associatedUser
    ]
]
def jsonData = groovy.json.JsonBuilder(postData).toString()
 
def publishCmd = "-u ${authMethod} -X POST -H \"Content-Type: application/json\" -d \"${jsonData}\" \"${apiEndpoint}\""
log.info("Publishing post: curl.exe ${publishCmd}")
ant.exec(
    append: true,
    failonerror: true,
    output: "logs/publish.log",
    executable: 'tools/curl/win/curl.exe'
) {
    arg(line: publishCmd)
}
log.info("Post published successfully.")
 
// Log result
def publishLog = new File("logs/publish.log").text
log.info("Publish result: ${publishLog}")

Tips for Best Results

  • Be specific: The more details you provide (fields, business rules, sample code), the better the AI output.
  • Leverage examples: Always paste existing scripts/templates as references when generating new ones.
  • Iterate: Review and test AI-generated code, then refine your prompt or provide more context if needed.
  • Include API endpoints and authentication details for integration scripts.

You’re now ready to use AI and automation to rapidly set up and customize your portal for any document type—no hand-coding required!