This document captures key learnings about the Pollyanna codebase discovered during implementation of the automatic archiving system.
/default/- Original template files that should never be edited directly/config/- Customized versions of default templates (this is where edits go)- When a file is missing in
/config/, the system automatically copies it from/default/ - Scripts live in
/default/template/perl/script/or/config/template/perl/script/ - Configuration files go in
/config/setting/admin/not/default/setting/admin/
- Uses
require_once()andensure_module()to manage dependencies - Templates are organized by type (perl, js, html, etc.) under
/template/directories - Themes are implemented as subdirectories under
/default/theme/ - The system uses
GetTemplate()function to load templates with theme override support
- Always use Perl taint mode (
perl -T) for all scripts - Required headers:
use strict; use warnings; use 5.010; use utf8; - Always restrict PATH for security:
$ENV{PATH} = "/bin:/usr/bin" - Use named subroutines with comments (e.g.,
sub BuildMessage { ... } # BuildMessage())
# Standard pattern for script dependencies:
require './utils.pl'; # Load utils.pl first
require_once('database.pl'); # Then use require_once for others
require_once('specific_module.pl');- Path Sanitization: Use
IsSaneFilename($path)for untainting file paths- This both validates AND untaints paths in one call
- Returns the clean path on success,
0on failure
- Manual taint patterns:
if ($var =~ m/^([^\s]+)$/) { $var = $1; } #security #taint - Always sanitize paths and directories with regex pattern matching before use
# Standard WriteLog pattern:
WriteLog('FunctionName: descriptive message; $var = ' . $var . '; caller = ' . join(',', caller));
# For warnings:
WriteLog('FunctionName: warning: error description; caller = ' . join(',', caller));
# For successful operations:
WriteLog('FunctionName: operation completed; caller = ' . join(',', caller));return 0;- For failed validations/boolean false conditionsreturn '';- For failed operations that should return stringsreturn;- For void functions that fail (no return value)return $value;- For successful operations returning data
- Use
die()for fatal errors - Use
WriteLog()for non-fatal information and warnings - Include verbose error messages and sanity checks for critical operations
- Primary database:
cache/b/index.sqlite3 - Default to append-only pattern for data storage
- Always sanitize SQL inputs and use proper error handling
- Maintain backward compatibility with older browsers
item_flat- Main item table with metadataitem_label- Labels/tags for itemsitem_parent- Thread/reply relationshipsitem_attribute- Additional item attributes
DBGetAllItemsInThread($itemHash)- Recursively gets all items in a threadDBDeleteItemReferences(@hashes)- Safely removes items from all related tablesSqliteQueryHashRef($query, @params)- Returns array of hashrefs for resultsSqliteGetValue($query, @params)- Returns single scalar value
- Items can have parent-child relationships stored in
item_parenttable DBGetAllItemsInThread()recursively follows these relationships- Threads should be treated atomically - don't break conversations by partial archival
- Items can be "pinned" using
#pinlabel initem_labeltable - Pinned items should be preserved regardless of age
- Pin detection:
SELECT COUNT(*) FROM item_label WHERE file_hash = ? AND label = 'pin'
- Text files stored in
html/txt/with hash-based subdirectory structure - Path pattern:
txt/{first2chars}/{next2chars}/{fullhash}.txt - Use
GetPathFromHash()to construct paths from hashes
- Manual archives use timestamp-based naming (epoch seconds)
- Automatic archives use date-based naming (
YYYY-MM-DD.tar.gz) - Archive directory structure:
archive/ ├── auto/ │ ├── YYYY-MM-DD/ │ │ ├── txt/ │ │ └── archive_log.txt │ └── YYYY-MM-DD.tar.gz
- Settings stored as simple text files in
/config/setting/admin/ - Use
GetConfig('setting/path/name')to read configuration values - Boolean settings:
1for true,0for false - Numeric settings: plain integer values
- Multiple themes can be active simultaneously via
GetActiveThemes() - Theme-specific overrides in
/default/theme/{theme_name}/template/ - Template resolution: theme templates override base templates
require_once($module)- PHP-style include-once functionalityensure_module($module)- Ensures module exists in config/ directoryWriteLog($message)- Standardized logging functionGetTemplate($name)- Template loading with theme supportGetConfig($path)- Configuration value retrieval
IsSaneFilename($path)- Path validation and untaintingGetFile($path)- Read file contentsPutFile($path, $content)- Write file contentsAppendFile($path, $content)- Append to filePutHtmlFile($path, $content)- Write HTML with special processing
IsItem($hash)- Validates and untaints item hashesIsFingerprint($key)- Validates cryptographic fingerprintsIsSaneFilename($path)- Validates and untaints file paths
./hike.sh buildor./build.sh- Build project./hike.sh clean [all|html]- Clean build artifacts./hike.sh startor./hike.sh startpython- Start server./hike.sh test- Basic test,python3 test/test.py- Selenium tests
./hike.sh db- SQLite CLI access./hike.sh guidb- SQLite browser GUI./hike.sh index [file]- Index data files./hike.sh refresh- Update templates from default
- All scripts must run with
-T(taint mode) - All external input must be validated and untainted
- System calls require untainted parameters
- Use established patterns like
IsSaneFilename()for validation
- Always validate file paths before system operations
- Use regex patterns to match expected input formats
- Log all validation failures with context
- Sanitize SQL inputs and use parameterized queries
- Restrict PATH environment variable
- Validate directory traversal attempts
- Use absolute paths where possible
- Log all file operations for audit trails
- Use indexed queries where possible
- Batch operations when processing multiple items
- Consider thread-level operations rather than individual items
- Maintain referential integrity during cleanup operations
- Thread-aware archiving prevents conversation fragmentation
- Compress archives for storage efficiency
- Use staging directories for atomic operations
- Clean up temporary files after successful operations
- GPG integration for signing/encryption
- Chain logging system for audit trails
- Access log processing for new content
- Template system for UI generation
- Archive scheduling via cron
- Archive restoration functionality
- Archive search and indexing
- Metrics and reporting dashboard
- Run syntax check:
perl -T -c script.pl - Test with disabled features first
- Verify configuration file handling
- Test edge cases (no items, validation failures)
- Monitor log output for proper debugging information
- Always backup before destructive operations
- Verify archive contents before database cleanup
- Test restoration procedures
- Validate thread relationship preservation
This knowledge base should serve as a reference for future development work on the Pollyanna project.