Overview
The contract management system in TradeMaster Transactions allows you to create, store, and manage legal agreements with clients. Contracts are stored in Firestore with PDF documents uploaded to Firebase Storage, providing a complete audit trail and easy access to all contractual obligations.
Contract Structure
Database Schema
Contracts are stored in the contracts collection in Firestore with the following structure:
{
"name" : "Event Management Agreement" ,
"description" : "Contract for managing XYZ Concert" ,
"user_name" : "John Doe Events" ,
"user_id" : "abc123" ,
"contract_id" : "CON-2024-001" ,
"contract_date" : Timestamp ,
"status" : true ,
"document" : "https://storage.googleapis.com/..." ,
"date" : {
"created" : Timestamp
}
}
Field Definitions
Field Type Description nameString Contract title descriptionString Detailed description of the contract user_nameString Client name user_idString Reference to client document ID contract_idString Unique contract identifier contract_dateTimestamp Date the contract was signed statusBoolean Active/inactive status documentString Firebase Storage URL to PDF date.createdTimestamp When the contract was created in the system
Creating Contracts
Required Permissions
To create contracts, users must have one of these roles:
Administrador - Full access
Cliente - Can create their own contracts
Coordinador - Can create contracts for clients
Contract Creation Flow
Select Client
Choose the client associated with this contract from the dropdown list.
Set Contract Date
Specify the date the contract was signed or executed.
Enter Contract Details
Provide the contract title, unique identifier, and description.
Upload PDF Document
Upload the signed contract PDF (required).
Submit for Creation
Review and submit to create the contract record.
Implementation Example
The contract creation form uses Formik for validation and Firebase for storage:
import * as Yup from 'yup' ;
import { useFormik } from 'formik' ;
import { Firestore , Storage , firebase } from '../../../guards/firebase/Firebase' ;
import { ref , uploadBytes , getDownloadURL } from "firebase/storage" ;
const newcontractSchema = Yup . object (). shape ({
name: Yup . string (). required ( 'El título es requerido' ),
description: Yup . string (). required ( 'Descripción es requerida' ),
contract_id: Yup . string (). required ( 'Identificador de contrato es requerido' ),
});
const formik = useFormik ({
initialValues: {
name: '' ,
description: '' ,
contract_id: '' ,
},
validationSchema: newcontractSchema ,
onSubmit : async ( values ) => {
// Create new document reference
const newRef = Firestore . collection ( 'contracts' ). doc ();
const newId = newRef . id ;
// Upload PDF to Firebase Storage
const storageRef = ref ( Storage , `contracts/ ${ newId } / ${ file . name } ` );
await uploadBytes ( storageRef , file );
const url = await getDownloadURL ( storageRef );
// Create contract document
await Firestore . collection ( 'contracts' ). doc ( newId ). set ({
name: values . name ,
description: values . description ,
user_name: selectedClient . name ,
user_id: selectedClient . client_id ,
contract_id: values . contract_id ,
contract_date: firebase . firestore . Timestamp . fromDate ( contractDate ),
status: true ,
document: url ,
date: { created: firebase . firestore . FieldValue . serverTimestamp () }
});
},
});
File Upload Handling
PDF Upload Requirements
Only PDF files are accepted for contract documents. The system validates file type before upload.
Storage Structure
Contract PDFs are organized in Firebase Storage:
contracts/
├── {contract_id_1}/
│ └── contract_document.pdf
├── {contract_id_2}/
│ └── agreement.pdf
└── {contract_id_3}/
└── service_contract.pdf
Upload Implementation
const handleUpload = async ( contractId , file ) => {
const storageRef = ref ( Storage , `contracts/ ${ contractId } / ${ file . name } ` );
await uploadBytes ( storageRef , file );
const downloadUrl = await getDownloadURL ( storageRef );
return downloadUrl ;
};
Addendums
What are Addendums?
Addendums are supplementary agreements that modify or add to existing contracts. They maintain a relationship with the parent contract while providing additional terms or changes.
Addendum Structure
Addendums follow a similar structure to contracts with additional fields:
{
"parent_contract_id" : "abc123" ,
"addendum_number" : 1 ,
"title" : "Payment Terms Amendment" ,
"description" : "Updated payment schedule" ,
"effective_date" : Timestamp ,
"document" : "https://storage.googleapis.com/..." ,
"status" : true ,
"date" : {
"created" : Timestamp
}
}
Creating Addendums
Addendums can be created by:
Navigating to an existing contract
Clicking “Create Addendum”
Filling in addendum details
Uploading the addendum PDF
Submitting for creation
Addendums are numbered sequentially and linked to their parent contract for easy reference.
Viewing Contracts
Contract List View
The contracts list displays all contracts with filtering and search capabilities:
Search by contract ID, client name, or title
Filter by status (active/inactive)
Sort by date, client, or contract ID
Quick actions for viewing details
Contract Detail View
The detail view provides comprehensive information:
Contract Status Management
Active vs Inactive
Contracts can be marked as active or inactive:
Active (status: true) : Currently in effect
Inactive (status: false) : Expired, terminated, or superseded
Changing Contract Status
await Firestore . collection ( 'contracts' ). doc ( contractId ). update ({
status: false ,
'date.deactivated' : firebase . firestore . FieldValue . serverTimestamp ()
});
Only administrators and the contract owner can change contract status.
Querying Contracts
Get All Contracts for a Client
const clientContracts = await Firestore . collection ( 'contracts' )
. where ( 'user_id' , '==' , clientId )
. where ( 'status' , '==' , true )
. orderBy ( 'contract_date' , 'desc' )
. get ();
Search Contracts by ID
const contract = await Firestore . collection ( 'contracts' )
. where ( 'contract_id' , '==' , 'CON-2024-001' )
. limit ( 1 )
. get ();
Get Contracts by Date Range
const startDate = firebase . firestore . Timestamp . fromDate ( new Date ( '2024-01-01' ));
const endDate = firebase . firestore . Timestamp . fromDate ( new Date ( '2024-12-31' ));
const contracts = await Firestore . collection ( 'contracts' )
. where ( 'contract_date' , '>=' , startDate )
. where ( 'contract_date' , '<=' , endDate )
. get ();
Client-Side Validation
Yup schema ensures data integrity:
const newcontractSchema = Yup . object (). shape ({
name: Yup . string ()
. required ( 'El título es requerido' )
. min ( 5 , 'Debe tener al menos 5 caracteres' ),
description: Yup . string ()
. required ( 'Descripción es requerida' )
. min ( 20 , 'Proporcione una descripción detallada' ),
contract_id: Yup . string ()
. required ( 'Identificador de contrato es requerido' )
. matches ( / ^ CON- \d {4} - \d {3} $ / , 'Formato: CON-YYYY-XXX' ),
});
Custom Validations
onSubmit : async ( values , { setErrors , setStatus }) => {
// Validate client is selected
if ( ! selectedClient ) {
setErrors ({ submit: "El cliente es requerido." });
return ;
}
// Validate PDF is uploaded
if ( selectedFiles . length === 0 ) {
setErrors ({ submit: "El documento pdf del contrato es requerido." });
return ;
}
// Check for duplicate contract ID
const existing = await Firestore . collection ( 'contracts' )
. where ( 'contract_id' , '==' , values . contract_id )
. limit ( 1 )
. get ();
if ( ! existing . empty ) {
setErrors ({ contract_id: "Este ID de contrato ya existe" });
return ;
}
}
Security Considerations
Implement Firestore security rules to restrict contract access
Ensure users can only view contracts they’re associated with
Use Firebase Storage rules to protect PDF documents
Store checksums of uploaded PDFs
Implement version control for contract modifications
Maintain audit logs of all contract changes
Encrypt sensitive contract terms
Implement data retention policies
Provide secure sharing mechanisms
Firestore Security Rules Example
rules_version = '2' ;
service cloud . firestore {
match / databases / { database } / documents {
match / contracts / { contractId } {
// Allow read if user is admin, contract owner, or staff
allow read : if request . auth != null &&
( get ( / databases / $ ( database ) / documents / u_clients / $ ( request . auth . uid )). data . account_type in [ 'Administrador' , 'Contador' , 'Coordinador' ] ||
resource . data . user_id == request . auth . uid );
// Allow write if user is admin, contract owner, or coordinator
allow write : if request . auth != null &&
get ( / databases / $ ( database ) / documents / u_clients / $ ( request . auth . uid )). data . account_type in [ 'Administrador' , 'Cliente' , 'Coordinador' ];
}
}
}
Best Practices
Consistent Naming Use a standardized contract ID format (e.g., CON-YYYY-XXX) for easy reference and sorting.
Detailed Descriptions Provide comprehensive descriptions to make contracts searchable and understandable at a glance.
Regular Backups Back up contract documents regularly to prevent data loss.
Audit Trail Maintain detailed logs of contract creation, modifications, and access.
Troubleshooting
Check file size - ensure it’s under Firebase Storage limits (default 10MB for free tier)
Verify file is actually a PDF
Check Firebase Storage rules allow uploads
Ensure stable internet connection
Contract Not Appearing in List
Verify contract was successfully created in Firestore
Check user has permission to view the contract
Ensure contract status is set correctly
Clear cache and refresh
Verify Storage URL is accessible
Check Firebase Storage CORS configuration
Ensure user is authenticated
Verify Storage security rules
Next Steps
Reconciliation Learn about financial reconciliation processes
Platform Settings Configure platform-wide settings