SpecM Database & API Specification
Overview
SpecM uses SQLite as its local database, stored in the OS application data directory. The Rust backend (Tauri) exposes 7 IPC commands that the Angular frontend consumes via @tauri-apps/api/core.
Database Location
| OS | Path |
|---|---|
| Windows | %LOCALAPPDATA%\com.specm.app\specm.db |
| macOS | ~/Library/Application Support/com.specm.app/specm.db |
| Linux | ~/.local/share/com.specm.app/specm.db |
Schema
categories
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT | Internal ID |
| name | TEXT | NOT NULL | Display name (e.g. "Architecture") |
| slug | TEXT | NOT NULL UNIQUE | URL-safe key (e.g. "architecture") |
| description | TEXT | Human-readable description |
Seed data: 8 categories (architecture, bug-detection, code-quality, code-style, documentation, migration, security, testing)
tools
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT | Internal ID |
| name | TEXT | NOT NULL | Display name (e.g. "ArchUnit") |
| slug | TEXT | NOT NULL UNIQUE | URL-safe key (e.g. "archunit") |
| description | TEXT | Human-readable description | |
| config_path | TEXT | Path to tool config file |
Seed data: 5 tools (archunit, checkstyle, spotbugs, sonarqube, openrewrite)
specs
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | TEXT | PRIMARY KEY | Spec ID (e.g. "ARCH-001") |
| version | TEXT | NOT NULL DEFAULT '1.0' | Semver version |
| title | TEXT | NOT NULL | Human-readable title |
| category | TEXT | NOT NULL, FK → categories(slug) | Category slug |
| severity | TEXT | NOT NULL DEFAULT 'major' | One of: critical, major, minor, info |
| applies_to | TEXT | Target scope: all, controller, service, repository | |
| config_ref | TEXT | Path + line pointer to enforcement config | |
| body | TEXT | NOT NULL | Markdown content |
| created_at | TEXT | DEFAULT datetime('now') | ISO-8601 creation timestamp |
| updated_at | TEXT | DEFAULT datetime('now') | ISO-8601 last update timestamp |
Seed data: 29 specs across 8 categories
spec_tools
Many-to-many relationship between specs and tools.
| Column | Type | Constraints | Description |
|---|---|---|---|
| spec_id | TEXT | NOT NULL, FK → specs(id) ON DELETE CASCADE | Spec ID |
| tool_slug | TEXT | NOT NULL, FK → tools(slug) | Tool slug |
Primary key: (spec_id, tool_slug)
Seed data: 37 relationships
spec_tags
Many-to-many relationship between specs and tags.
| Column | Type | Constraints | Description |
|---|---|---|---|
| spec_id | TEXT | NOT NULL, FK → specs(id) ON DELETE CASCADE | Spec ID |
| tag | TEXT | NOT NULL | Tag string |
Primary key: (spec_id, tag)
Seed data: 83 tags
spec_dependencies
Many-to-many relationship between specs (dependency tracking).
| Column | Type | Constraints | Description |
|---|---|---|---|
| spec_id | TEXT | NOT NULL, FK → specs(id) ON DELETE CASCADE | Spec ID |
| depends_on | TEXT | NOT NULL | Target spec ID |
Primary key: (spec_id, depends_on)
specs_fts
FTS5 virtual table for full-text search.
| Column | Source |
|---|---|
| id | specs.id |
| title | specs.title |
| body | specs.body |
| category | specs.category |
| tags | (aggregated from spec_tags) |
Usage: SELECT * FROM specs_fts WHERE specs_fts MATCH 'keyword'
Entity Relationship Diagram
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│ categories │ │ specs │ │ tools │
├──────────────┤ ├──────────────────┤ ├──────────────┤
│ id (PK) │◄──┐ │ id (PK) │ ┌──►│ id (PK) │
│ name │ │ │ version │ │ │ name │
│ slug (UQ) │───┼───│ category (FK) │ │ │ slug (UQ) │
│ description │ │ │ title │ │ │ description │
└──────────────┘ │ │ severity │ │ │ config_path │
│ │ applies_to │ │ └──────────────┘
│ │ config_ref │ │
│ │ body │ │ ┌──────────────┐
│ │ created_at │ │ │ spec_tools │
│ │ updated_at │ │ ├──────────────┤
│ └────────┬────┬────┘ │ │ spec_id (FK) │
│ │ │ │ │ tool_slug(FK)│
│ │ │ │ └──────────────┘
│ │ │ │
│ ┌────────┘ │ │
│ │ │ │
│ │ ┌──────────┘ ┌────┘
│ │ │ │
│ ▼ ▼ ▼
│ ┌──────────────┐ ┌──────────────────┐
│ │ spec_tags │ │ spec_dependencies │
│ ├──────────────┤ ├──────────────────┤
│ │ spec_id (FK) │ │ spec_id (FK) │
│ │ tag │ │ depends_on │
│ └──────────────┘ └──────────────────┘
│
└── categories(slug) referenced by specs(category)
Tauri IPC Commands
All commands are invoked via invoke() from @tauri-apps/api/core.
list_specs
list_specs(category?: string): Result<Spec[], string>
Returns all specs, optionally filtered by category slug. Results ordered by spec ID.
Parameters:
- category (optional): Filter by category slug. null or omitted returns all.
Response: Array of Spec objects with tools, tags, and depends_on populated.
get_spec
get_spec(spec_id: string): Result<Spec | null, string>
Returns a single spec by ID, or null if not found.
Response: Spec object with all relationships populated.
create_spec
create_spec(spec: CreateSpec): Result<Spec, string>
Creates a new spec with its tools, tags, and dependencies.
Request body:
{
id: string; // e.g. "ARCH-006"
version: string; // e.g. "1.0"
title: string;
category: string; // category slug
severity: string; // "critical" | "major" | "minor" | "info"
applies_to: string | null;
config_ref: string | null;
body: string; // Markdown content
tools: string[]; // tool slugs
tags: string[]; // tag strings
depends_on: string[]; // spec IDs
}
Response: The newly created Spec object.
delete_spec
delete_spec(spec_id: string): Result<boolean, string>
Deletes a spec and its cascading relationships (spec_tools, spec_tags, spec_dependencies).
Response: true if deleted, false if not found.
list_categories
list_categories(): Result<Category[], string>
Returns all categories ordered by name.
Response: Array of Category objects.
list_tools
list_tools(): Result<Tool[], string>
Returns all tools ordered by name.
Response: Array of Tool objects.
validate_specs
validate_specs(): Result<ValidationResult, string>
Validates all specs against: - Severity must be one of: critical, major, minor, info - Tool slugs must be one of: archunit, checkstyle, spotbugs, sonarqube, openrewrite
Response:
{
passed: string[]; // spec IDs that passed
failed: Array<{
spec_id: string;
errors: string[]; // e.g. ["invalid severity: warning", "unknown tool: pmd"]
}>;
}
TypeScript Types
interface Spec {
id: string;
version: string;
title: string;
category: string;
tools: string[];
severity: string;
applies_to: string | null;
tags: string[];
depends_on: string[];
config_ref: string | null;
body: string;
created_at: string;
updated_at: string;
}
interface CreateSpec {
id: string;
version: string;
title: string;
category: string;
tools: string[];
severity: string;
applies_to: string | null;
tags: string[];
depends_on: string[];
config_ref: string | null;
body: string;
}
interface Category {
id: number;
name: string;
slug: string;
description: string | null;
}
interface Tool {
id: number;
name: string;
slug: string;
description: string | null;
config_path: string | null;
}
interface ValidationError {
spec_id: string;
errors: string[];
}
interface ValidationResult {
passed: string[];
failed: ValidationError[];
}
Current Data Summary
| Table | Count |
|---|---|
| categories | 8 |
| tools | 5 |
| specs | 29 |
| spec_tools | 37 |
| spec_tags | 83 |