This feature (002-direct-db-access) enables scripts to query schedule data directly via SQL after loading XER files through MCP. Key additions: - spec.md: Feature specification with 3 user stories - plan.md: Implementation plan with constitution check - research.md: Technology decisions (SQLite file, WAL mode, atomic writes) - data-model.md: DatabaseInfo, SchemaInfo, TableInfo entities - contracts/mcp-tools.json: Extended load_xer schema, new get_database_info tool - quickstart.md: Usage examples for direct database access - tasks.md: 16 implementation tasks across 6 phases
182 lines
5.3 KiB
Markdown
182 lines
5.3 KiB
Markdown
# Data Model: Direct Database Access for Scripts
|
|
|
|
**Date**: 2026-01-08
|
|
**Branch**: `002-direct-db-access`
|
|
|
|
## Entity Overview
|
|
|
|
```
|
|
┌─────────────────┐
|
|
│ DatabaseInfo │
|
|
└─────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
│ SchemaInfo │───────│ TableInfo │
|
|
└─────────────────┘ └─────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────┐
|
|
│ ColumnInfo │
|
|
└─────────────────┘
|
|
```
|
|
|
|
## New Entities
|
|
|
|
### DatabaseInfo
|
|
|
|
Information about the current database connection, returned by load operations and queryable separately.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| db_path | string | Yes | Absolute path to SQLite database file; `:memory:` for in-memory |
|
|
| is_persistent | boolean | Yes | True if file-based, false if in-memory |
|
|
| source_file | string | No | Path to XER file that was loaded |
|
|
| loaded_at | datetime | Yes | When data was loaded |
|
|
| schema | SchemaInfo | Yes | Database schema information |
|
|
|
|
**Validation Rules**:
|
|
- db_path must be an absolute path (or `:memory:`)
|
|
- loaded_at must be ISO 8601 format
|
|
|
|
### SchemaInfo
|
|
|
|
Metadata describing the database structure.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| tables | list[TableInfo] | Yes | All tables in the database |
|
|
| version | string | Yes | Schema version (matches server version) |
|
|
|
|
### TableInfo
|
|
|
|
Information about a single database table.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| name | string | Yes | Table name |
|
|
| columns | list[ColumnInfo] | Yes | Column definitions |
|
|
| primary_key | list[string] | Yes | Column(s) forming primary key |
|
|
| foreign_keys | list[ForeignKeyInfo] | No | Foreign key relationships |
|
|
| row_count | integer | Yes | Number of rows in table |
|
|
|
|
### ColumnInfo
|
|
|
|
Information about a single column.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| name | string | Yes | Column name |
|
|
| type | string | Yes | SQLite data type (TEXT, INTEGER, REAL, etc.) |
|
|
| nullable | boolean | Yes | Whether NULL values are allowed |
|
|
| default | string | No | Default value if any |
|
|
|
|
### ForeignKeyInfo
|
|
|
|
Foreign key relationship information.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| column | string | Yes | Column in this table |
|
|
| references_table | string | Yes | Referenced table |
|
|
| references_column | string | Yes | Referenced column |
|
|
|
|
## Extended load_xer Response
|
|
|
|
The existing load_xer tool response is extended with database information:
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"project": { ... },
|
|
"activity_count": 4440,
|
|
"relationship_count": 8583,
|
|
"database": {
|
|
"db_path": "/path/to/schedule.sqlite",
|
|
"is_persistent": true,
|
|
"source_file": "/path/to/schedule.xer",
|
|
"loaded_at": "2026-01-08T14:30:00",
|
|
"schema": {
|
|
"version": "0.2.0",
|
|
"tables": [
|
|
{
|
|
"name": "activities",
|
|
"columns": [
|
|
{"name": "task_id", "type": "TEXT", "nullable": false},
|
|
{"name": "task_name", "type": "TEXT", "nullable": false},
|
|
...
|
|
],
|
|
"primary_key": ["task_id"],
|
|
"foreign_keys": [
|
|
{"column": "proj_id", "references_table": "projects", "references_column": "proj_id"}
|
|
],
|
|
"row_count": 4440
|
|
},
|
|
...
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## New Tool Input Schema
|
|
|
|
### load_xer (extended)
|
|
|
|
New optional parameter:
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| db_path | string | No | Path for persistent database file. If omitted, uses in-memory database. If empty string, auto-generates path from XER filename. |
|
|
|
|
### get_database_info
|
|
|
|
No input parameters required. Returns current database information.
|
|
|
|
## SQLite Schema (Unchanged)
|
|
|
|
The underlying database schema remains unchanged from feature 001-schedule-tools:
|
|
|
|
- `projects` - Project metadata
|
|
- `activities` - Task/activity data
|
|
- `relationships` - Predecessor/successor relationships
|
|
- `wbs` - Work breakdown structure
|
|
- `calendars` - Calendar definitions
|
|
|
|
The difference is storage location (file vs memory), not structure.
|
|
|
|
## Query Examples for Scripts
|
|
|
|
Once scripts have the database path, they can execute standard SQL:
|
|
|
|
```python
|
|
import sqlite3
|
|
|
|
# Connect using path from load_xer response
|
|
conn = sqlite3.connect("/path/to/schedule.sqlite")
|
|
|
|
# Query activities
|
|
cursor = conn.execute("""
|
|
SELECT task_code, task_name, target_start_date, target_end_date
|
|
FROM activities
|
|
WHERE task_type = 'TT_Mile'
|
|
ORDER BY target_start_date
|
|
""")
|
|
|
|
for row in cursor:
|
|
print(row)
|
|
```
|
|
|
|
```sql
|
|
-- Find critical path activities
|
|
SELECT task_code, task_name, total_float_hr_cnt
|
|
FROM activities
|
|
WHERE driving_path_flag = 1
|
|
ORDER BY target_start_date;
|
|
|
|
-- Join activities with WBS
|
|
SELECT a.task_code, a.task_name, w.wbs_name
|
|
FROM activities a
|
|
JOIN wbs w ON a.wbs_id = w.wbs_id;
|
|
```
|