Storage Architecture
File-based JSON storage for all persistent data in data/ directory.
File Structure
Data directory: /data/
Stored files:
pinterest_tokens.json– OAuth tokens and account informationboards.json– Cached Pinterest board data per accountpin_counts.json– Rate limit tracking timestamps per accountmodel_settings.json– OpenAI model selection per Discord guildrestart_info.json– Temporary restart context (auto-deleted)*.txt– System prompt sections (user-created, not in repository)
JSON File Operations
File manager: src/utils/jsonFileManager.js
Core operations:
readJsonFile(filename)– Read and parse JSON filewriteJsonFile(filename, data)– Write object as formatted JSONreadTextFile(filename)– Read text file content
Read behavior:
- Returns parsed object if file exists
- Returns empty object
{}if file not found (ENOENT) - Throws error for other failures (permissions, invalid JSON)
Write behavior:
- Creates data/ directory if missing (recursive)
- Writes JSON with 2-space indentation
- Overwrites existing files
- Throws error on write failures
Error handling:
- File not found: Returns default value (empty object)
- Parse errors: Logged and thrown
- Write errors: Logged and thrown
Pinterest Token Storage
File: pinterest_tokens.json
Structure:
{
"discord_user_id": {
"accounts": {
"pinterest_user_id": {
"accessToken": "pint_bearer_token",
"pinterestUserId": "pinterest_id",
"accountName": "username (id_prefix)",
"createdAt": "2025-10-01T12:00:00.000Z"
}
},
"activeAccount": "pinterest_user_id"
}
}
Key relationships:
- Discord user ID → Multiple Pinterest accounts
- Pinterest user ID → Single account data object
- Active account → Pinterest user ID reference
Account data fields:
accessToken– OAuth bearer token for API requestspinterestUserId– Unique Pinterest account identifieraccountName– Display name:username (first8chars)createdAt– ISO 8601 timestamp of account linking
Operations:
- Add account: Creates nested structure if Discord user new
- First account: Automatically set as active
- Switch account: Updates activeAccount reference
- Delete account: Not implemented (manual file edit required)
Board Cache Storage
File: boards.json
Structure:
{
"pinterest_user_id": [
{
"id": "board_identifier",
"name": "Board Name"
}
]
}
Key relationships:
- Pinterest user ID → Array of board objects
- Each account maintains separate board list
Board data fields:
id– Pinterest API board identifiername– User-visible board name
Update mechanism:
- Full replacement on
/synccommand - No incremental updates
- No automatic synchronization
Usage:
- Board name validation in
/pincommand - Case-insensitive matching
- Must sync before first pin operation
Rate Limit Storage
File: pin_counts.json
Structure:
{
"pinterest_user_id": [
1727784000000,
1727784120000,
1727784240000
]
}
Key relationships:
- Pinterest user ID → Array of pin timestamps
- Each timestamp = one successful pin
Timestamp format:
Unix milliseconds (Date.now())
Sliding window implementation:
- Load all timestamps for account
- Filter timestamps within last 12 hours (43,200,000ms)
- Count remaining timestamps
- Record new pin by adding timestamp
- Save filtered + new timestamps
Automatic cleanup:
Old timestamps (>12 hours) filtered out on every operation.
Limit enforcement:
- Maximum 100 timestamps per account
- Pre-flight check before pin batch
- Real-time check before each pin
Model Settings Storage
File: model_settings.json
Structure:
{
"discord_guild_id": "openai_model_id"
}
Key relationships:
- Discord guild ID → Single OpenAI model ID
- One model per guild
Model ID format:
OpenAI model identifier (e.g., "gpt-5", "o3-mini")
Operations:
- Get model: Returns null if guild not configured
- Set model: Creates or updates guild entry
- No default model: Guilds must explicitly configure
Validation:
No validation on save. Assumes model ID from /model command already filtered.
Restart Context Storage
File: restart_info.json
Lifecycle: Temporary (created on restart, deleted on reconnection)
Structure:
{
"channelId": "discord_channel_id",
"messageId": "discord_message_id",
"timestamp": 1727784000000
}
Usage:
- Created by
/restartcommand before exit - Read by bot on reconnection
- Used to update restart message
- Deleted after successful update
Error handling:
If update fails:
- Error logged
- File still deleted
- Bot continues normal operation
Data Directory Management
Creation:
data/ directory created automatically on first write operation.
Permissions:
Requires write access to application directory.
Version control:
- data/ directory excluded from git (.gitignore)
- System prompt .txt files user-created, not in repository
- Empty data/ structure created on deployment
Backup:
No automatic backup. Critical data stored in single directory for easy backup.
Migration:
No migration system. Manual file editing required for schema changes.