Skip to main content

Overview

Energy CMMS provides enterprise document control with revision management, AI-powered search, interactive PDF annotations, and full traceability.

Document Hierarchy

Documents are organized hierarchically:

Core Concepts

Document Types

Classify documents: Drawings, Manuals, Procedures, Certificates

Disciplines

Technical areas: Electrical, Mechanical, Civil, HVAC

Revisions

Version control with automatic tracking

Creating Documents

1

Navigate to Documents

Go to Documents > Documents
2

Add New Document

Click “Add Document” button
3

Basic Information

  • Code: Unique identifier (auto-generated or manual)
  • Title: Descriptive name
  • Type: Document classification
  • Discipline: Technical area
4

Upload File

Create first revision:
  • Upload PDF file
  • Set revision number (e.g., “A”, “Rev 0”)
  • Add revision notes
  • System triggers AI extraction
5

Configure Metadata

Fill dynamic fields:
  • Fields auto-created from document type
  • Can be filled manually
  • Or auto-extracted via AI

Document Model

documento = Documento.objects.create(
    codigo="DWG-ELEC-001",
    titulo="Substation A Single Line Diagram",
    tipo_documento=electrical_drawing_type,
    disciplina=electrical_discipline,
    estado_actual='EN_REVISION',
    responsable=engineer,
    fecha_inicio=date.today()
)

# Create first revision
revision = Revision.objects.create(
    documento=documento,
    numero_revision="A",
    archivo=uploaded_pdf,
    cambios="Initial issue"
)

Revision Control

Revision Workflow

When document changes:
  1. Upload new PDF version
  2. Increment revision number
  3. Document what changed
  4. Previous revision marked as superseded
  5. New revision becomes current

Accessing Revisions

# Get current revision
current = documento.ultima_revision

# Get all revisions chronologically
historial = documento.revisiones.all().order_by('-fecha_carga')

# Compare two revisions
rev_a = documento.revisiones.get(numero_revision='A')
rev_b = documento.revisiones.get(numero_revision='B')
All revisions are retained. You can always access previous versions for audit trails or rollback.

AI-Powered Features

Automatic Text Extraction

When PDF is uploaded, n8n workflow:
1

Upload Triggers Webhook

# Django sends webhook to n8n
payload = {
    'documento_id': doc.id,
    'filepath': revision.archivo.name,
    'callback_url': f"{settings.SITE_URL}/documentos/api/update-texto/{doc.id}/"
}
requests.post(settings.N8N_EXTRACT_TEXTO_WEBHOOK_URL, json=payload)
2

n8n Extracts Text

Workflow performs:
  • PDF to text conversion (OCR if needed)
  • Text cleanup and formatting
  • Page-by-page extraction
3

Callback with Results

n8n posts back:
{
  "documento_id": 123,
  "texto": "Full extracted text...",
  "pages": 45
}
4

Generate Embeddings

Django Celery task:
  • Chunks text into fragments
  • Generates vector embeddings via Gemini
  • Stores in pgvector for semantic search

Metadata Extraction

AI can auto-fill metadata fields:
# Trigger AI metadata extraction
webhook_url = settings.N8N_METADATA_SYNC_WEBHOOK
payload = {
    'documento_id': doc.id,
    'file_url': doc.ultima_revision.archivo.url,
    'metadatos': [
        {'nombre': 'project_number', 'etiqueta': 'Project Number'},
        {'nombre': 'drawing_scale', 'etiqueta': 'Scale'},
        {'nombre': 'date_issued', 'etiqueta': 'Date Issued'}
    ]
}
response = requests.post(webhook_url, json=payload)
AI extraction works best on structured documents like drawings with title blocks. Results may vary on handwritten or low-quality scans.

Dynamic Metadata

Customize metadata per document type:

Configuring Metadata Fields

1

Define Fields for Type

Go to Documents > Metadata Configurations:
  • Link to document type
  • Add field configurations
2

Field Configuration

For each field:
  • Name: Internal field name (e.g., project_number)
  • Label: Display name (e.g., “Project Number”)
  • Field Type: TEXT, NUMBER, DATE, SELECT, BOOLEAN, RELATIONAL
  • Required: Mandatory for approval
  • Order: Display sequence
3

Relational Fields

Link to other models:
  • Content Type: Select related model (Asset, Location, etc.)
  • Display Field: Which field to show
  • Creates dropdown with autocomplete

Example Metadata Config

# Drawing-specific metadata
configs = [
    MetadatoConfig(
        tipo_documento=drawing_type,
        nombre='drawing_number',
        etiqueta='Drawing Number',
        tipo_campo='TEXT',
        es_requerido=True,
        orden=1
    ),
    MetadatoConfig(
        tipo_documento=drawing_type,
        nombre='scale',
        etiqueta='Scale',
        tipo_campo='SELECT',
        opciones_select='1:50,1:100,1:200,NTS',
        orden=2
    ),
    MetadatoConfig(
        tipo_documento=drawing_type,
        nombre='related_equipment',
        etiqueta='Related Equipment',
        tipo_campo='RELATIONAL',
        content_type=ContentType.objects.get_for_model(Activo),
        campo_relacional='nombre',
        orden=3
    )
]

Interactive PDF Viewer

Annotate and collaborate on documents:

Pin System

Comment Pins

Add notes and discussions to specific locations on PDF

Markup Pins

Highlight areas for review or clarification

Issue Pins

Flag errors or required changes

Link Pins

Connect to other documents or assets

Adding Annotations

1

Open Document Viewer

Click document to open interactive PDF viewer
2

Select Pin Type

Choose annotation type from toolbar
3

Place Pin

Click on PDF where comment applies:
  • Point pin: Single click
  • Area pin: Click and drag rectangle
4

Add Content

Fill in annotation:
  • Text comment
  • Assign to responsible person
  • Attach images
  • Link to other documents

Pin Features

comentario = ComentarioDocumento.objects.create(
    documento=doc,
    revision=current_revision,
    usuario=request.user,
    responsable=assigned_engineer,
    texto="Verify transformer rating matches spec",
    tipo='ISSUE',
    posicion_x=450.5,
    posicion_y=320.8,
    pagina=3,
    resuelto=False
)

# Attach image
ComentarioImagen.objects.create(
    comentario=comentario,
    imagen=uploaded_photo
)

# Link to related document
comentario.vinculos.add(related_spec_document)
Pins are tied to specific revisions. When document is revised, pins from previous revisions remain visible but are marked as “from superseded revision”.

Document Traceability

Track document relationships and history:

Relationship Types

Response documents:
  • RFI responses
  • Transmittals
  • Review comments
response_doc = Documento.objects.create(
    codigo="RFI-RESP-001",
    titulo="Response to RFI-001",
    respuesta_a=original_rfi  # Parent link
)

Traceability View

Visualize complete document network:
# Get full traceability tree
tree = build_traceability_tree(documento)

# Returns hierarchical structure:
{
    'documento': documento,
    'parent': parent_doc,
    'children': [child1, child2],
    'revisions': [rev_a, rev_b, rev_c],
    'linked_docs': [doc1, doc2]  # Via pins
}
Use the Traceability Viewer to see the complete document ecosystem. Helpful for impact analysis when making changes.

Search Capabilities

Quick lookup by code or title:
# Simple search
results = Documento.objects.filter(
    Q(codigo__icontains=query) | Q(titulo__icontains=query)
).select_related('tipo_documento', 'disciplina')[:20]

Advanced Filters

Multi-criteria search:
Filter combination:
  • Document type (Drawing, Manual, etc.)
  • Discipline (Electrical, Mechanical, etc.)
  • Status (Draft, Approved, Superseded)
Temporal filtering:
  • Created between dates
  • Modified after date
  • Issued in specific period
AI-powered content search:
1

User Enters Query

Natural language question:
  • “transformer protection relay settings”
  • “fire pump installation procedure”
  • “electrical room ventilation requirements”
2

Generate Query Vector

import google.generativeai as genai

genai.configure(api_key=settings.GEMINI_API_KEY)
result = genai.embed_content(
    model="models/text-embedding-004",
    content=query,
    task_type="retrieval_query"
)
query_vector = result['embedding']
3

Search Vector Database

Find similar document fragments:
from pgvector.django import CosineDistance

fragments = DocumentoFragmento.objects.annotate(
    distance=CosineDistance('embedding', query_vector)
).order_by('distance')[:40]
4

Rank and Return

Results include:
  • Document metadata
  • Relevant excerpt
  • Similarity score
  • Page number
System combines exact matching (code/title) with semantic search (content) for best results.
# Hybrid search implementation
results = []

# 1. Exact matches (highest priority)
exact_matches = Documento.objects.filter(
    Q(codigo__iexact=query) | Q(titulo__icontains=query)
)[:5]

# 2. Semantic matches
vector_results = semantic_search(query, limit=15)

# 3. Merge without duplicates
for doc in exact_matches:
    results.append({'doc': doc, 'score': 1.0, 'match_type': 'exact'})

for item in vector_results:
    if item['doc_id'] not in [r['doc'].id for r in results]:
        results.append({
            'doc': item['document'],
            'score': item['similarity'],
            'match_type': 'semantic',
            'excerpt': item['fragment_text']
        })

Document Libraries

Organize documents into collections:

Creating Libraries

1

Define Library

Create named collection:
  • Name (e.g., “Project X Drawings”)
  • Description
  • Access permissions
2

Add Documents

Multiple selection methods:
  • Manual selection
  • Filter-based rules
  • Bulk import
3

Configure View

Library settings:
  • Default sort order
  • Visible columns
  • Export formats

Library Use Cases

Project Sets

All documents for specific project

Submittal Packages

Documents for client approval

As-Built Set

Final construction documents

O&M Manuals

Operations and maintenance docs

Document States

Workflow through document lifecycle:
Initial creation:
  • Being prepared
  • Not for distribution
  • Can be freely edited

Bulk Operations

Mass Upload

Import many documents at once:
1

Prepare Package

Organize files:
  • Consistent naming convention
  • Metadata in filename or CSV
  • All PDFs in folder
2

Create Import Mapping

Define extraction rules:
# Filename format: PROJ-DISC-TYPE-NUM-REV.pdf
# Example: P001-ELEC-DWG-0001-A.pdf

pattern = r'(?P<project>\w+)-(?P<discipline>\w+)-(?P<type>\w+)-(?P<number>\d+)-(?P<revision>\w+).pdf'
3

Execute Import

System processes:
  • Extract metadata from filename
  • Create document records
  • Upload PDFs
  • Trigger AI extraction
  • Generate preview thumbnails

Batch Updates

Update multiple documents:
# Bulk state change
Documento.objects.filter(
    tipo_documento=drawing_type,
    proyecto='P001'
).update(
    estado_actual='ISSUED',
    fecha_emision=date.today()
)

# Bulk metadata update
for doc in Documento.objects.filter(codigo__startswith='ELEC-'):
    MetadatoValor.objects.update_or_create(
        documento=doc,
        config=project_field_config,
        defaults={'valor': 'Project Alpha'}
    )

AI Chat Assistant

Interactive document Q&A:

Using AI Chat

1

Open Document

View any document with extracted text
2

Click Chat Icon

Open AI assistant panel
3

Ask Questions

Examples:
  • “What is the maximum load on Bus A?”
  • “Summarize the testing procedure”
  • “List all protection relay settings”
4

Get Answers

AI responds with:
  • Answer based on document content
  • Specific page references
  • Relevant excerpts

Chat Implementation

# Proxy to n8n AI workflow
response = requests.post(
    settings.N8N_CHAT_WEBHOOK_URL,
    json={
        'documento_id': doc.id,
        'contenido_texto': doc.contenido_texto,  # Full text for context
        'pregunta': user_question,
        'historial': previous_chat_messages
    },
    timeout=60
)

ai_answer = response.json()['respuesta']
AI answers are generated from document content but may contain errors. Always verify critical information against the source PDF.

Access Control

Manage document visibility:

Permission Levels

Everyone can view:
  • Safety procedures
  • General manuals
  • Policy documents

Best Practices

Standardize document codes:
  • Project prefix
  • Discipline code
  • Document type
  • Sequential number
Example: P001-ELEC-DWG-0042
Descriptive naming:
  • Include location/equipment
  • Specify what is shown
  • Avoid generic names
Good: “Substation A - 13.8kV Switchgear Single Line” Bad: “Electrical Drawing 1”
Quality control:
  • Verify metadata completeness
  • Check for superseded docs still in use
  • Validate cross-references
  • Ensure AI extraction succeeded
Lifecycle management:
  • Define retention periods
  • Archive inactive documents
  • Purge obsolete versions (keep one)
  • Backup critical documents

Integration Points

With Assets

  • Link drawings to equipment
  • Manuals attached to asset records
  • Certificates for compliance tracking

With Maintenance

  • Procedures linked to routines
  • Work instructions in work orders
  • As-built drawings for repairs

With Projects

  • Submittal tracking
  • RFI management
  • Change order documentation

Reporting

Standard Reports

Document Register

Complete listing with metadata

Transmittal Log

Documents sent/received tracking

Review Status

Pending approvals and comments

Superseded List

Documents ready for archival

Next Steps:

Build docs developers (and LLMs) love