docs: add specification and implementation plan for direct database access feature
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
This commit is contained in:
181
specs/002-direct-db-access/data-model.md
Normal file
181
specs/002-direct-db-access/data-model.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# 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;
|
||||
```
|
||||
Reference in New Issue
Block a user