This commit is contained in:
+78
-78
@@ -15,7 +15,7 @@ Welcome to the **Antigravity Edition** of Spec-Kit. This system is architected t
|
||||
In this edition, Spec-Kit commands have been split into two interactive layers:
|
||||
|
||||
1. **Workflows (`/command`)**: High-level orchestrations that guide the agent through a series of logical steps. **The easiest way to run a skill is by typing its corresponding workflow command.**
|
||||
2. **Skills (`@speckit.name`)**: Packaged agentic capabilities. Mentions of a skill give the agent immediate context and autonomous "know-how" to execute the specific toolset associated with that phase.
|
||||
2. **Skills (`@speckit-name`)**: Packaged agentic capabilities. Mentions of a skill give the agent immediate context and autonomous "know-how" to execute the specific toolset associated with that phase.
|
||||
|
||||
> **To understand the power of Skills in Antigravity, read the docs here:**
|
||||
> [https://antigravity.google/docs/skills](https://antigravity.google/docs/skills)
|
||||
@@ -38,15 +38,15 @@ Some skills and scripts reference a `.specify/` directory for templates and proj
|
||||
```text
|
||||
.specify/
|
||||
├── templates/
|
||||
│ ├── spec-template.md # Template for /speckit.specify
|
||||
│ ├── plan-template.md # Template for /speckit.plan
|
||||
│ ├── tasks-template.md # Template for /speckit.tasks
|
||||
│ ├── spec-template.md # Template for /speckit-specify
|
||||
│ ├── plan-template.md # Template for /speckit-plan
|
||||
│ ├── tasks-template.md # Template for /speckit-tasks
|
||||
│ └── agent-file-template.md # Template for update-agent-context.sh
|
||||
└── memory/
|
||||
└── constitution.md # Project governance rules (/speckit.constitution)
|
||||
└── constitution.md # Project governance rules (/speckit-constitution)
|
||||
```
|
||||
|
||||
> **Note:** If `.specify/` is absent, skills will still function — they'll create blank files instead of using templates. The constitution workflow (`/speckit.constitution`) will create this structure for you on first run.
|
||||
> **Note:** If `.specify/` is absent, skills will still function — they'll create blank files instead of using templates. The constitution workflow (`/speckit-constitution`) will create this structure for you on first run.
|
||||
|
||||
---
|
||||
|
||||
@@ -59,34 +59,34 @@ The toolkit is organized into modular components that provide both the logic (Sc
|
||||
├── skills/ # @ Mentions (Agent Intelligence)
|
||||
│ ├── nestjs-best-practices/ # NestJS Architecture Patterns
|
||||
│ ├── next-best-practices/ # Next.js App Router Patterns
|
||||
│ ├── speckit.analyze/ # Consistency Checker
|
||||
│ ├── speckit.checker/ # Static Analysis Aggregator
|
||||
│ ├── speckit.checklist/ # Requirements Validator
|
||||
│ ├── speckit.clarify/ # Ambiguity Resolver
|
||||
│ ├── speckit.constitution/ # Governance Manager
|
||||
│ ├── speckit.diff/ # Artifact Comparator
|
||||
│ ├── speckit.implement/ # Code Builder (Anti-Regression)
|
||||
│ ├── speckit.migrate/ # Legacy Code Migrator
|
||||
│ ├── speckit.plan/ # Technical Planner
|
||||
│ ├── speckit.quizme/ # Logic Challenger (Red Team)
|
||||
│ ├── speckit.reviewer/ # Code Reviewer
|
||||
│ ├── speckit.security-audit/ # Security Auditor (OWASP/CASL/ClamAV)
|
||||
│ ├── speckit.specify/ # Feature Definer
|
||||
│ ├── speckit.status/ # Progress Dashboard
|
||||
│ ├── speckit.tasks/ # Task Breaker
|
||||
│ ├── speckit.taskstoissues/ # Issue Tracker Syncer (GitHub + Gitea)
|
||||
│ ├── speckit.tester/ # Test Runner & Coverage
|
||||
│ └── speckit.validate/ # Implementation Validator
|
||||
│ ├── speckit-analyze/ # Consistency Checker
|
||||
│ ├── speckit-checker/ # Static Analysis Aggregator
|
||||
│ ├── speckit-checklist/ # Requirements Validator
|
||||
│ ├── speckit-clarify/ # Ambiguity Resolver
|
||||
│ ├── speckit-constitution/ # Governance Manager
|
||||
│ ├── speckit-diff/ # Artifact Comparator
|
||||
│ ├── speckit-implement/ # Code Builder (Anti-Regression)
|
||||
│ ├── speckit-migrate/ # Legacy Code Migrator
|
||||
│ ├── speckit-plan/ # Technical Planner
|
||||
│ ├── speckit-quizme/ # Logic Challenger (Red Team)
|
||||
│ ├── speckit-reviewer/ # Code Reviewer
|
||||
│ ├── speckit-security-audit/ # Security Auditor (OWASP/CASL/ClamAV)
|
||||
│ ├── speckit-specify/ # Feature Definer
|
||||
│ ├── speckit-status/ # Progress Dashboard
|
||||
│ ├── speckit-tasks/ # Task Breaker
|
||||
│ ├── speckit-taskstoissues/ # Issue Tracker Syncer (GitHub + Gitea)
|
||||
│ ├── speckit-tester/ # Test Runner & Coverage
|
||||
│ └── speckit-validate/ # Implementation Validator
|
||||
│
|
||||
├── workflows/ # / Slash Commands (Orchestration)
|
||||
│ ├── 00-speckit.all.md # Full Pipeline (10 steps: Specify → Validate)
|
||||
│ ├── 01–11-speckit.*.md # Individual phase workflows
|
||||
│ ├── speckit.prepare.md # Prep Pipeline (5 steps: Specify → Analyze)
|
||||
│ ├── 00-speckit-all.md # Full Pipeline (10 steps: Specify → Validate)
|
||||
│ ├── 01–11-speckit-*.md # Individual phase workflows
|
||||
│ ├── speckit-prepare.md # Prep Pipeline (5 steps: Specify → Analyze)
|
||||
│ ├── schema-change.md # DB Schema Change (ADR-009)
|
||||
│ ├── create-backend-module.md # NestJS Module Scaffolding
|
||||
│ ├── create-frontend-page.md # Next.js Page Scaffolding
|
||||
│ ├── deploy.md # Deployment via Gitea CI/CD
|
||||
│ └── util-speckit.*.md # Utilities (checklist, diff, migrate, etc.)
|
||||
│ └── util-speckit-*.md # Utilities (checklist, diff, migrate, etc.)
|
||||
│
|
||||
└── scripts/
|
||||
├── bash/ # Bash Core (Kinetic logic)
|
||||
@@ -112,27 +112,27 @@ The toolkit is organized into modular components that provide both the logic (Sc
|
||||
|
||||
| Phase | Workflow Trigger | Antigravity Skill | Role |
|
||||
| :---------------- | :---------------------------- | :------------------------ | :------------------------------------------------------ |
|
||||
| **Full Pipeline** | `/00-speckit.all` | N/A | Runs full SDLC pipeline (10 steps: Specify → Validate). |
|
||||
| **Governance** | `/01-speckit.constitution` | `@speckit.constitution` | Establishes project rules & principles. |
|
||||
| **Definition** | `/02-speckit.specify` | `@speckit.specify` | Drafts structured `spec.md`. |
|
||||
| **Ambiguity** | `/03-speckit.clarify` | `@speckit.clarify` | Resolves gaps post-spec. |
|
||||
| **Architecture** | `/04-speckit.plan` | `@speckit.plan` | Generates technical `plan.md`. |
|
||||
| **Decomposition** | `/05-speckit.tasks` | `@speckit.tasks` | Breaks plans into atomic tasks. |
|
||||
| **Consistency** | `/06-speckit.analyze` | `@speckit.analyze` | Cross-checks Spec vs Plan vs Tasks. |
|
||||
| **Execution** | `/07-speckit.implement` | `@speckit.implement` | Builds implementation with safety protocols. |
|
||||
| **Quality** | `/08-speckit.checker` | `@speckit.checker` | Runs static analysis (Linting, Security, Types). |
|
||||
| **Testing** | `/09-speckit.tester` | `@speckit.tester` | Runs test suite & reports coverage. |
|
||||
| **Review** | `/10-speckit.reviewer` | `@speckit.reviewer` | Performs code review (Logic, Perf, Style). |
|
||||
| **Validation** | `/11-speckit.validate` | `@speckit.validate` | Verifies implementation matches Spec requirements. |
|
||||
| **Preparation** | `/speckit.prepare` | N/A | Runs Specify → Analyze prep sequence (5 steps). |
|
||||
| **Full Pipeline** | `/00-speckit-all` | N/A | Runs full SDLC pipeline (10 steps: Specify → Validate). |
|
||||
| **Governance** | `/01-speckit-constitution` | `@speckit-constitution` | Establishes project rules & principles. |
|
||||
| **Definition** | `/02-speckit-specify` | `@speckit-specify` | Drafts structured `spec.md`. |
|
||||
| **Ambiguity** | `/03-speckit-clarify` | `@speckit-clarify` | Resolves gaps post-spec. |
|
||||
| **Architecture** | `/04-speckit-plan` | `@speckit-plan` | Generates technical `plan.md`. |
|
||||
| **Decomposition** | `/05-speckit-tasks` | `@speckit-tasks` | Breaks plans into atomic tasks. |
|
||||
| **Consistency** | `/06-speckit-analyze` | `@speckit-analyze` | Cross-checks Spec vs Plan vs Tasks. |
|
||||
| **Execution** | `/07-speckit-implement` | `@speckit-implement` | Builds implementation with safety protocols. |
|
||||
| **Quality** | `/08-speckit-checker` | `@speckit-checker` | Runs static analysis (Linting, Security, Types). |
|
||||
| **Testing** | `/09-speckit-tester` | `@speckit-tester` | Runs test suite & reports coverage. |
|
||||
| **Review** | `/10-speckit-reviewer` | `@speckit-reviewer` | Performs code review (Logic, Perf, Style). |
|
||||
| **Validation** | `/11-speckit-validate` | `@speckit-validate` | Verifies implementation matches Spec requirements. |
|
||||
| **Preparation** | `/speckit-prepare` | N/A | Runs Specify → Analyze prep sequence (5 steps). |
|
||||
| **Schema** | `/schema-change` | N/A | DB schema changes per ADR-009 (no migrations). |
|
||||
| **Security** | N/A | `@speckit.security-audit` | OWASP Top 10 + CASL + ClamAV audit. |
|
||||
| **Checklist** | `/util-speckit.checklist` | `@speckit.checklist` | Generates feature checklists. |
|
||||
| **Diff** | `/util-speckit.diff` | `@speckit.diff` | Compares artifact versions. |
|
||||
| **Migration** | `/util-speckit.migrate` | `@speckit.migrate` | Port existing code to Spec-Kit. |
|
||||
| **Red Team** | `/util-speckit.quizme` | `@speckit.quizme` | Challenges logical flaws. |
|
||||
| **Status** | `/util-speckit.status` | `@speckit.status` | Shows feature completion status. |
|
||||
| **Tracking** | `/util-speckit.taskstoissues` | `@speckit.taskstoissues` | Syncs tasks to GitHub/Gitea issues. |
|
||||
| **Security** | N/A | `@speckit-security-audit` | OWASP Top 10 + CASL + ClamAV audit. |
|
||||
| **Checklist** | `/util-speckit-checklist` | `@speckit-checklist` | Generates feature checklists. |
|
||||
| **Diff** | `/util-speckit-diff` | `@speckit-diff` | Compares artifact versions. |
|
||||
| **Migration** | `/util-speckit-migrate` | `@speckit-migrate` | Port existing code to Spec-Kit. |
|
||||
| **Red Team** | `/util-speckit-quizme` | `@speckit-quizme` | Challenges logical flaws. |
|
||||
| **Status** | `/util-speckit-status` | `@speckit-status` | Shows feature completion status. |
|
||||
| **Tracking** | `/util-speckit-taskstoissues` | `@speckit-taskstoissues` | Syncs tasks to GitHub/Gitea issues. |
|
||||
|
||||
---
|
||||
|
||||
@@ -142,14 +142,14 @@ The following skills are designed to work together as a comprehensive defense ag
|
||||
|
||||
| Step | Skill | Core Question | Focus |
|
||||
| :-------------- | :------------------ | :-------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **1. Checker** | `@speckit.checker` | _"Is the code compliant?"_ | **Syntax & Security**. Runs compilation, linting (ESLint/GolangCI), and vulnerability scans (npm audit/govulncheck). Catches low-level errors first. |
|
||||
| **2. Tester** | `@speckit.tester` | _"Does it work?"_ | **Functionality**. Executes your test suite (Jest/Pytest/Go Test) to ensure logic performs as expected and tests pass. |
|
||||
| **3. Reviewer** | `@speckit.reviewer` | _"Is the code written well?"_ | **Quality & Maintainability**. Analyzes code structure for complexity, performance bottlenecks, and best practices, acting as a senior peer reviewer. |
|
||||
| **4. Validate** | `@speckit.validate` | _"Did we build the right thing?"_ | **Requirements**. Semantically compares the implementation against the defined `spec.md` and `plan.md` to ensure all feature requirements are met. |
|
||||
| **1. Checker** | `@speckit-checker` | _"Is the code compliant?"_ | **Syntax & Security**. Runs compilation, linting (ESLint/GolangCI), and vulnerability scans (npm audit/govulncheck). Catches low-level errors first. |
|
||||
| **2. Tester** | `@speckit-tester` | _"Does it work?"_ | **Functionality**. Executes your test suite (Jest/Pytest/Go Test) to ensure logic performs as expected and tests pass. |
|
||||
| **3. Reviewer** | `@speckit-reviewer` | _"Is the code written well?"_ | **Quality & Maintainability**. Analyzes code structure for complexity, performance bottlenecks, and best practices, acting as a senior peer reviewer. |
|
||||
| **4. Validate** | `@speckit-validate` | _"Did we build the right thing?"_ | **Requirements**. Semantically compares the implementation against the defined `spec.md` and `plan.md` to ensure all feature requirements are met. |
|
||||
|
||||
> **🤖 Power User Tip:** You can amplify this pipeline by creating a custom **MCP Server** or subagent that delegates heavy reasoning to a dedicated LLM.
|
||||
>
|
||||
> - **Use Case:** Bind the `@speckit.validate` and `@speckit.reviewer` steps to a large-context model.
|
||||
> - **Use Case:** Bind the `@speckit-validate` and `@speckit-reviewer` steps to a large-context model.
|
||||
> - **Benefit:** Large-context models (1M+ tokens) excel at analyzing the full project context against the Spec, finding subtle logical flaws that smaller models miss.
|
||||
> - **How:** Create a wrapper script `scripts/gemini-reviewer.sh` that pipes the `tasks.md` and codebase to an LLM, then expose this as a tool.
|
||||
|
||||
@@ -161,28 +161,28 @@ These workflows function as the "Control Plane" of the project, managing everyth
|
||||
|
||||
| Step | Workflow | Core Question | Focus |
|
||||
| :----------------- | :-------------------------------------------------- | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **1. Preparation** | `/speckit.prepare` | _"Are we ready?"_ | **The Macro-Workflow**. Runs Skills 02–06 (Specify $\to$ Clarify $\to$ Plan $\to$ Tasks $\to$ Analyze) in one sequence to go from "Idea" to "Ready to Code". |
|
||||
| **2. Migration** | `/util-speckit.migrate` | _"Can we import?"_ | **Onboarding**. Reverse-engineers existing code into `spec.md`, `plan.md`, and `tasks.md`. |
|
||||
| **3. Red Team** | `/util-speckit.quizme` | _"What did we miss?"_ | **Hardening**. Socratic questioning to find logical gaps in your specification before you plan. |
|
||||
| **4. Export** | `/util-speckit.taskstoissues` | _"Who does what?"_ | **Handoff**. Converts your `tasks.md` into GitHub or Gitea issues with labels and milestones. |
|
||||
| **5. Status** | `/util-speckit.status` | _"Are we there yet?"_ | **Tracking**. Scans all artifacts to report feature completion percentage. |
|
||||
| **6. Utilities** | `/util-speckit.diff` <br> `/util-speckit.checklist` | _"What changed?"_ | **Support**. View artifact diffs or generate quick acceptance checklists. |
|
||||
| **1. Preparation** | `/speckit-prepare` | _"Are we ready?"_ | **The Macro-Workflow**. Runs Skills 02–06 (Specify $\to$ Clarify $\to$ Plan $\to$ Tasks $\to$ Analyze) in one sequence to go from "Idea" to "Ready to Code". |
|
||||
| **2. Migration** | `/util-speckit-migrate` | _"Can we import?"_ | **Onboarding**. Reverse-engineers existing code into `spec.md`, `plan.md`, and `tasks.md`. |
|
||||
| **3. Red Team** | `/util-speckit-quizme` | _"What did we miss?"_ | **Hardening**. Socratic questioning to find logical gaps in your specification before you plan. |
|
||||
| **4. Export** | `/util-speckit-taskstoissues` | _"Who does what?"_ | **Handoff**. Converts your `tasks.md` into GitHub or Gitea issues with labels and milestones. |
|
||||
| **5. Status** | `/util-speckit-status` | _"Are we there yet?"_ | **Tracking**. Scans all artifacts to report feature completion percentage. |
|
||||
| **6. Utilities** | `/util-speckit-diff` <br> `/util-speckit-checklist` | _"What changed?"_ | **Support**. View artifact diffs or generate quick acceptance checklists. |
|
||||
|
||||
### 🔄 The Design Sequence
|
||||
|
||||
**Stage 1: Inception**
|
||||
|
||||
- _Legacy Project?_ $\to$ Run **`/util-speckit.migrate`**.
|
||||
- _New Feature?_ $\to$ Run **`/speckit.prepare`**.
|
||||
- _Legacy Project?_ $\to$ Run **`/util-speckit-migrate`**.
|
||||
- _New Feature?_ $\to$ Run **`/speckit-prepare`**.
|
||||
|
||||
**Stage 2: Hardening**
|
||||
|
||||
- Run **`/util-speckit.quizme`** to catch edge cases.
|
||||
- Run **`/speckit.prepare`** again to regenerate the Plan based on restricted specs.
|
||||
- Run **`/util-speckit-quizme`** to catch edge cases.
|
||||
- Run **`/speckit-prepare`** again to regenerate the Plan based on restricted specs.
|
||||
|
||||
**Stage 3: Handoff**
|
||||
|
||||
- Run **`/util-speckit.taskstoissues`** to sync with your board.
|
||||
- Run **`/util-speckit-taskstoissues`** to sync with your board.
|
||||
|
||||
---
|
||||
|
||||
@@ -192,17 +192,17 @@ Once the `.agents` folder is present, you can talk to your agent as a partner. Y
|
||||
|
||||
**Example Conversation:**
|
||||
|
||||
> **Developer**: "**/02-speckit.specify** Add a real-time notification system using WebSockets."
|
||||
> **Developer**: "**/02-speckit-specify** Add a real-time notification system using WebSockets."
|
||||
>
|
||||
> **Antigravity**: "Understood. Executing the **@speckit.specify** skill. Creating feature branch `005-notifications` and drafting the initial specification..."
|
||||
> **Antigravity**: "Understood. Executing the **@speckit-specify** skill. Creating feature branch `005-notifications` and drafting the initial specification..."
|
||||
> _(Antigravity creates branch, drafts spec.md)_
|
||||
>
|
||||
> **Antigravity**: "Specification ready. I've identified some ambiguity in the reconnection strategy. Should I use **@speckit.clarify** to resolve this?"
|
||||
> **Antigravity**: "Specification ready. I've identified some ambiguity in the reconnection strategy. Should I use **@speckit-clarify** to resolve this?"
|
||||
>
|
||||
> **Developer**: "Yes, use **@speckit.clarify**."
|
||||
> **Developer**: "Yes, use **@speckit-clarify**."
|
||||
> _(Antigravity executes the skill logic, interviewing the developer and updating the spec)_
|
||||
>
|
||||
> **Antigravity**: "The spec is now robust. I'm ready to trigger **/04-speckit.plan** and **/05-speckit.tasks** to prepare for implementation."
|
||||
> **Antigravity**: "The spec is now robust. I'm ready to trigger **/04-speckit-plan** and **/05-speckit-tasks** to prepare for implementation."
|
||||
|
||||
---
|
||||
|
||||
@@ -212,7 +212,7 @@ To get the most out of this system, follow these **Spec-Driven Development (SDD)
|
||||
|
||||
### 1. The Constitution is King 👑
|
||||
|
||||
**Never skip `/01-speckit.constitution`.**
|
||||
**Never skip `/01-speckit-constitution`.**
|
||||
|
||||
- This file is the "Context Window Anchor" for the AI.
|
||||
- It prevents hallucinations about tech stack (e.g., "Don't use jQuery" or "Always use TypeScript strict mode").
|
||||
@@ -222,9 +222,9 @@ To get the most out of this system, follow these **Spec-Driven Development (SDD)
|
||||
|
||||
Don't rush to code. The workflow exists to catch errors _cheaply_ before they become expensive bugs.
|
||||
|
||||
- **Ambiguity Layer**: `/03-speckit.clarify` catches misunderstandings.
|
||||
- **Logic Layer**: `/util-speckit.quizme` catches edge cases.
|
||||
- **Consistency Layer**: `/06-speckit.analyze` catches gaps between Spec and Plan.
|
||||
- **Ambiguity Layer**: `/03-speckit-clarify` catches misunderstandings.
|
||||
- **Logic Layer**: `/util-speckit-quizme` catches edge cases.
|
||||
- **Consistency Layer**: `/06-speckit-analyze` catches gaps between Spec and Plan.
|
||||
|
||||
### 3. The 15-Minute Rule ⏱️
|
||||
|
||||
@@ -240,17 +240,17 @@ If you change your mind mid-project:
|
||||
|
||||
1. Don't just edit the code.
|
||||
2. Edit the `spec.md` to reflect the new requirement.
|
||||
3. Run `/util-speckit.diff` to see the drift.
|
||||
3. Run `/util-speckit-diff` to see the drift.
|
||||
4. This keeps your documentation alive and truthful.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Adaptation Notes
|
||||
|
||||
- **Skill-Based Autonomy**: Mentions like `@speckit.plan` trigger the agent's internalized understanding of how to perform that role.
|
||||
- **Skill-Based Autonomy**: Mentions like `@speckit-plan` trigger the agent's internalized understanding of how to perform that role.
|
||||
- **Shared Script Core**: Logic resides in `.agents/scripts/bash` (modular) with PowerShell equivalents in `scripts/powershell/` for Windows-native execution.
|
||||
- **Agent-Native**: Designed to be invoked via Antigravity tool calls and reasoning rather than just terminal strings.
|
||||
- **LCBP3-DMS Specific**: Includes project-specific skills (`nestjs-best-practices`, `next-best-practices`, `speckit.security-audit`) and workflows (`/schema-change`, `/create-backend-module`, `/deploy`).
|
||||
- **LCBP3-DMS Specific**: Includes project-specific skills (`nestjs-best-practices`, `next-best-practices`, `speckit-security-audit`) and workflows (`/schema-change`, `/create-backend-module`, `/deploy`).
|
||||
|
||||
---
|
||||
|
||||
@@ -287,8 +287,8 @@ If you change your mind mid-project:
|
||||
| Create Frontend Page | `/create-frontend-page` | Next.js App Router page |
|
||||
| Schema Change | `/schema-change` | ADR-009: No migrations |
|
||||
| Deploy | `/deploy` | Blue-Green via Gitea CI/CD |
|
||||
| UAT Feature Check | `/11-speckit.validate` | vs `01-05-acceptance-criteria.md` |
|
||||
| Security Audit | `@speckit.security-audit` | OWASP + CASL + ClamAV |
|
||||
| UAT Feature Check | `/11-speckit-validate` | vs `01-05-acceptance-criteria.md` |
|
||||
| Security Audit | `@speckit-security-audit` | OWASP + CASL + ClamAV |
|
||||
|
||||
### 🚫 Critical Forbidden Actions
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: speckit.analyze
|
||||
name: speckit-analyze
|
||||
description: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.tasks
|
||||
- speckit-tasks
|
||||
---
|
||||
|
||||
## User Input
|
||||
@@ -21,13 +21,13 @@ You are the **Antigravity Consistency Analyst**. Your role is to identify incons
|
||||
## Task
|
||||
|
||||
### Goal
|
||||
Identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. This command MUST run only after `/speckit.tasks` has successfully produced a complete `tasks.md`.
|
||||
Identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. This command MUST run only after `/speckit-tasks` has successfully produced a complete `tasks.md`.
|
||||
|
||||
## Operating Constraints
|
||||
|
||||
**STRICTLY READ-ONLY**: Do **not** modify any files. Output a structured analysis report. Offer an optional remediation plan (user must explicitly approve before any follow-up editing commands would be invoked manually).
|
||||
|
||||
**Constitution Authority**: The project constitution (`.specify/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit.analyze`.
|
||||
**Constitution Authority**: The project constitution (`.specify/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit-analyze`.
|
||||
|
||||
### Steps
|
||||
|
||||
@@ -163,9 +163,9 @@ Output a Markdown report (no file writes) with the following structure:
|
||||
|
||||
At end of report, output a concise Next Actions block:
|
||||
|
||||
- If CRITICAL issues exist: Recommend resolving before `/speckit.implement`
|
||||
- If CRITICAL issues exist: Recommend resolving before `/speckit-implement`
|
||||
- If only LOW/MEDIUM: User may proceed, but provide improvement suggestions
|
||||
- Provide explicit command suggestions: e.g., "Run /speckit.specify with refinement", "Run /speckit.plan to adjust architecture", "Manually edit tasks.md to add coverage for 'performance-metrics'"
|
||||
- Provide explicit command suggestions: e.g., "Run /speckit-specify with refinement", "Run /speckit-plan to adjust architecture", "Manually edit tasks.md to add coverage for 'performance-metrics'"
|
||||
|
||||
### 8. Offer Remediation
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: speckit.checker
|
||||
name: speckit-checker
|
||||
description: Run static analysis tools and aggregate results.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: speckit.checklist
|
||||
name: speckit-checklist
|
||||
description: Generate a custom checklist for the current feature based on user requirements.
|
||||
version: 1.0.0
|
||||
---
|
||||
@@ -101,7 +101,7 @@ You are the **Antigravity Quality Gatekeeper**. Your role is to validate the qua
|
||||
- Format: `[domain].md`
|
||||
- If file exists, append to existing file
|
||||
- Number items sequentially starting from CHK001
|
||||
- Each `/speckit.checklist` run creates a NEW file (never overwrites existing checklists)
|
||||
- Each `/speckit-checklist` run creates a NEW file (never overwrites existing checklists)
|
||||
|
||||
**CORE PRINCIPLE - Test the Requirements, Not the Implementation**:
|
||||
Every checklist item MUST evaluate the REQUIREMENTS THEMSELVES for:
|
||||
@@ -219,7 +219,7 @@ You are the **Antigravity Quality Gatekeeper**. Your role is to validate the qua
|
||||
- Actor/timing
|
||||
- Any explicit user-specified must-have items incorporated
|
||||
|
||||
**Important**: Each `/speckit.checklist` command invocation creates a checklist file using short, descriptive names unless file already exists. This allows:
|
||||
**Important**: Each `/speckit-checklist` command invocation creates a checklist file using short, descriptive names unless file already exists. This allows:
|
||||
|
||||
- Multiple checklists of different types (e.g., `ux.md`, `test.md`, `security.md`)
|
||||
- Simple, memorable filenames that indicate checklist purpose
|
||||
+2
-2
@@ -4,13 +4,13 @@
|
||||
**Created**: [DATE]
|
||||
**Feature**: [Link to spec.md or relevant documentation]
|
||||
|
||||
**Note**: This checklist is generated by the `/speckit.checklist` command based on feature context and requirements.
|
||||
**Note**: This checklist is generated by the `/speckit-checklist` command based on feature context and requirements.
|
||||
|
||||
<!--
|
||||
============================================================================
|
||||
IMPORTANT: The checklist items below are SAMPLE ITEMS for illustration only.
|
||||
|
||||
The /speckit.checklist command MUST replace these with actual items based on:
|
||||
The /speckit-checklist command MUST replace these with actual items based on:
|
||||
- User's specific checklist request
|
||||
- Feature requirements from spec.md
|
||||
- Technical context from plan.md
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
name: speckit.clarify
|
||||
name: speckit-clarify
|
||||
description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.specify
|
||||
- speckit-specify
|
||||
handoffs:
|
||||
- label: Build Technical Plan
|
||||
agent: speckit.plan
|
||||
agent: speckit-plan
|
||||
prompt: Create a plan for the spec. I am building with...
|
||||
---
|
||||
|
||||
@@ -28,7 +28,7 @@ You are the **Antigravity Ambiguity Buster**. Your role is to interrogate specif
|
||||
|
||||
Goal: Detect and reduce ambiguity or missing decision points in the active feature specification and record the clarifications directly in the spec file.
|
||||
|
||||
Note: This clarification workflow is expected to run (and be completed) BEFORE invoking `/speckit.plan`. If the user explicitly states they are skipping clarification (e.g., exploratory spike), you may proceed, but must warn that downstream rework risk increases.
|
||||
Note: This clarification workflow is expected to run (and be completed) BEFORE invoking `/speckit-plan`. If the user explicitly states they are skipping clarification (e.g., exploratory spike), you may proceed, but must warn that downstream rework risk increases.
|
||||
|
||||
Execution steps:
|
||||
|
||||
@@ -36,7 +36,7 @@ Execution steps:
|
||||
- `FEATURE_DIR`
|
||||
- `FEATURE_SPEC`
|
||||
- (Optionally capture `IMPL_PLAN`, `TASKS` for future chained flows.)
|
||||
- If JSON parsing fails, abort and instruct user to re-run `/speckit.specify` or verify feature branch environment.
|
||||
- If JSON parsing fails, abort and instruct user to re-run `/speckit-specify` or verify feature branch environment.
|
||||
- For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
|
||||
2. Load the current spec file. Perform a structured ambiguity & coverage scan using this taxonomy. For each category, mark status: Clear / Partial / Missing. Produce an internal coverage map used for prioritization (do not output raw map unless no questions will be asked).
|
||||
@@ -175,13 +175,13 @@ Execution steps:
|
||||
- Path to updated spec.
|
||||
- Sections touched (list names).
|
||||
- Coverage summary table listing each taxonomy category with Status: Resolved (was Partial/Missing and addressed), Deferred (exceeds question quota or better suited for planning), Clear (already sufficient), Outstanding (still Partial/Missing but low impact).
|
||||
- If any Outstanding or Deferred remain, recommend whether to proceed to `/speckit.plan` or run `/speckit.clarify` again later post-plan.
|
||||
- If any Outstanding or Deferred remain, recommend whether to proceed to `/speckit-plan` or run `/speckit-clarify` again later post-plan.
|
||||
- Suggested next command.
|
||||
|
||||
Behavior rules:
|
||||
|
||||
- If no meaningful ambiguities found (or all potential questions would be low-impact), respond: "No critical ambiguities detected worth formal clarification." and suggest proceeding.
|
||||
- If spec file missing, instruct user to run `/speckit.specify` first (do not create a new spec here).
|
||||
- If spec file missing, instruct user to run `/speckit-specify` first (do not create a new spec here).
|
||||
- Never exceed 5 total asked questions (clarification retries for a single question do not count as new questions).
|
||||
- Avoid speculative tech stack questions unless the absence blocks functional clarity.
|
||||
- Respect user early termination signals ("stop", "done", "proceed").
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
---
|
||||
name: speckit.constitution
|
||||
name: speckit-constitution
|
||||
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
|
||||
version: 1.0.0
|
||||
handoffs:
|
||||
- label: Build Specification
|
||||
agent: speckit.specify
|
||||
agent: speckit-specify
|
||||
prompt: Implement the feature specification based on the updated constitution. I want to build...
|
||||
---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: speckit.diff
|
||||
name: speckit-diff
|
||||
description: Compare two versions of a spec or plan to highlight changes.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: speckit.implement
|
||||
name: speckit-implement
|
||||
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md (with Ironclad Anti-Regression Protocols)
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.tasks
|
||||
- speckit-tasks
|
||||
---
|
||||
|
||||
## User Input
|
||||
@@ -245,4 +245,4 @@ At the start of execution and after every 3 modifications:
|
||||
|
||||
---
|
||||
|
||||
Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list.
|
||||
Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit-tasks` first to regenerate the task list.
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: speckit.migrate
|
||||
name: speckit-migrate
|
||||
description: Migrate existing projects into the speckit structure by generating spec.md, plan.md, and tasks.md from existing code.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
name: speckit.plan
|
||||
name: speckit-plan
|
||||
description: Execute the implementation planning workflow using the plan template to generate design artifacts.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.specify
|
||||
- speckit-specify
|
||||
handoffs:
|
||||
- label: Create Tasks
|
||||
agent: speckit.tasks
|
||||
agent: speckit-tasks
|
||||
prompt: Break the plan into tasks
|
||||
send: true
|
||||
- label: Create Checklist
|
||||
agent: speckit.checklist
|
||||
agent: speckit-checklist
|
||||
prompt: Create a checklist for the following domain...
|
||||
---
|
||||
|
||||
+7
-7
@@ -3,7 +3,7 @@
|
||||
**Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
|
||||
**Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
**Note**: This template is filled in by the `/speckit-plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
|
||||
```text
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
├── plan.md # This file (/speckit-plan command output)
|
||||
├── research.md # Phase 0 output (/speckit-plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit-plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit-plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit-plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
name: speckit.quizme
|
||||
name: speckit-quizme
|
||||
description: Challenge the specification with Socratic questioning to identify logical gaps, unhandled edge cases, and robustness issues.
|
||||
version: 1.0.0
|
||||
handoffs:
|
||||
- label: Clarify Spec Requirements
|
||||
agent: speckit.clarify
|
||||
agent: speckit-clarify
|
||||
prompt: Clarify specification requirements
|
||||
---
|
||||
|
||||
@@ -24,7 +24,7 @@ You are the **Antigravity Red Teamer**. Your role is to play the "Socratic Teach
|
||||
|
||||
### Outline
|
||||
|
||||
Goal: Act as a "Red Team" or "Socratic Teacher" to challenge the current feature specification. Unlike `speckit.clarify` (which looks for missing definitions), `speckit.quizme` looks for logical fallacies, race conditions, naive assumptions, and "happy path" bias.
|
||||
Goal: Act as a "Red Team" or "Socratic Teacher" to challenge the current feature specification. Unlike `speckit-clarify` (which looks for missing definitions), `speckit-quizme` looks for logical fallacies, race conditions, naive assumptions, and "happy path" bias.
|
||||
|
||||
Execution steps:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: speckit.reviewer
|
||||
name: speckit-reviewer
|
||||
description: Perform code review with actionable feedback and suggestions.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: speckit.security-audit
|
||||
name: speckit-security-audit
|
||||
description: Perform a security-focused audit of the codebase against OWASP Top 10, CASL authorization, and LCBP3-DMS security requirements.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.checker
|
||||
- speckit-checker
|
||||
---
|
||||
|
||||
## Role
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: speckit.specify
|
||||
name: speckit-specify
|
||||
description: Create or update the feature specification from a natural language feature description.
|
||||
version: 1.0.0
|
||||
handoffs:
|
||||
- label: Build Technical Plan
|
||||
agent: speckit.plan
|
||||
agent: speckit-plan
|
||||
prompt: Create a plan for the spec. I am building with...
|
||||
- label: Clarify Spec Requirements
|
||||
agent: speckit.clarify
|
||||
agent: speckit-clarify
|
||||
prompt: Clarify specification requirements
|
||||
send: true
|
||||
---
|
||||
@@ -28,7 +28,7 @@ You are the **Antigravity Domain Scribe**. Your role is to translate natural lan
|
||||
|
||||
### Outline
|
||||
|
||||
The text the user typed after `/speckit.specify` in the triggering message **is** the feature description. Assume you always have it available in this conversation even if `{{args}}` appears literally below. Do not ask the user to repeat it unless they provided an empty command.
|
||||
The text the user typed after `/speckit-specify` in the triggering message **is** the feature description. Assume you always have it available in this conversation even if `{{args}}` appears literally below. Do not ask the user to repeat it unless they provided an empty command.
|
||||
|
||||
Given that feature description, do this:
|
||||
|
||||
@@ -143,7 +143,7 @@ Given that feature description, do this:
|
||||
|
||||
## Notes
|
||||
|
||||
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
||||
- Items marked incomplete require spec updates before `/speckit-clarify` or `/speckit-plan`
|
||||
```
|
||||
|
||||
b. **Run Validation Check**: Review the spec against each checklist item:
|
||||
@@ -196,7 +196,7 @@ Given that feature description, do this:
|
||||
|
||||
d. **Update Checklist**: After each validation iteration, update the checklist file with current pass/fail status
|
||||
|
||||
7. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit.clarify` or `/speckit.plan`).
|
||||
7. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit-clarify` or `/speckit-plan`).
|
||||
|
||||
**NOTE:** The script creates and checks out the new branch and initializes the spec file before writing.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: speckit.status
|
||||
name: speckit-status
|
||||
description: Display a dashboard showing feature status, completion percentage, and blockers.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
name: speckit.tasks
|
||||
name: speckit-tasks
|
||||
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.plan
|
||||
- speckit-plan
|
||||
handoffs:
|
||||
- label: Analyze For Consistency
|
||||
agent: speckit.analyze
|
||||
agent: speckit-analyze
|
||||
prompt: Run a project analysis for consistency
|
||||
send: true
|
||||
- label: Implement Project
|
||||
agent: speckit.implement
|
||||
agent: speckit-implement
|
||||
prompt: Start the implementation in phases
|
||||
send: true
|
||||
---
|
||||
+1
-1
@@ -29,7 +29,7 @@ description: "Task list template for feature implementation"
|
||||
============================================================================
|
||||
IMPORTANT: The tasks below are SAMPLE TASKS for illustration purposes only.
|
||||
|
||||
The /speckit.tasks command MUST replace these with actual tasks based on:
|
||||
The /speckit-tasks command MUST replace these with actual tasks based on:
|
||||
- User stories from spec.md (with their priorities P1, P2, P3...)
|
||||
- Feature requirements from plan.md
|
||||
- Entities from data-model.md
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: speckit.taskstoissues
|
||||
name: speckit-taskstoissues
|
||||
description: Convert existing tasks into actionable, dependency-ordered issues for the feature based on available design artifacts.
|
||||
version: 1.1.0
|
||||
depends-on:
|
||||
- speckit.tasks
|
||||
- speckit-tasks
|
||||
tools: ['github/github-mcp-server/issue_write']
|
||||
---
|
||||
|
||||
@@ -112,7 +112,7 @@ Convert all tasks from `tasks.md` into well-structured issues on the appropriate
|
||||
|
||||
---
|
||||
|
||||
_Auto-generated by speckit.taskstoissues from `tasks.md`_
|
||||
_Auto-generated by speckit-taskstoissues from `tasks.md`_
|
||||
```
|
||||
|
||||
7. **Apply Labels** — Assign labels based on task metadata:
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: speckit.tester
|
||||
name: speckit-tester
|
||||
description: Execute tests, measure coverage, and report results.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: speckit.validate
|
||||
name: speckit-validate
|
||||
description: Validate that implementation matches specification requirements.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.implement
|
||||
- speckit-implement
|
||||
---
|
||||
|
||||
## User Input
|
||||
@@ -2,79 +2,79 @@
|
||||
description: Run the full speckit pipeline from specification to analysis in one command.
|
||||
---
|
||||
|
||||
# Workflow: speckit.all
|
||||
# Workflow: speckit-all
|
||||
|
||||
This meta-workflow orchestrates the **complete development lifecycle**, from specification through implementation and validation. For the preparation-only pipeline (steps 1-5), use `/speckit.prepare` instead.
|
||||
This meta-workflow orchestrates the **complete development lifecycle**, from specification through implementation and validation. For the preparation-only pipeline (steps 1-5), use `/speckit-prepare` instead.
|
||||
|
||||
## Preparation Phase (Steps 1-5)
|
||||
|
||||
1. **Specify** (`/speckit.specify`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.specify/SKILL.md`
|
||||
1. **Specify** (`/speckit-specify`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-specify/SKILL.md`
|
||||
- Execute with user's feature description
|
||||
- Creates: `spec.md`
|
||||
|
||||
2. **Clarify** (`/speckit.clarify`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.clarify/SKILL.md`
|
||||
2. **Clarify** (`/speckit-clarify`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-clarify/SKILL.md`
|
||||
- Execute to resolve ambiguities
|
||||
- Updates: `spec.md`
|
||||
|
||||
3. **Plan** (`/speckit.plan`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.plan/SKILL.md`
|
||||
3. **Plan** (`/speckit-plan`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-plan/SKILL.md`
|
||||
- Execute to create technical design
|
||||
- Creates: `plan.md`
|
||||
|
||||
4. **Tasks** (`/speckit.tasks`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.tasks/SKILL.md`
|
||||
4. **Tasks** (`/speckit-tasks`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-tasks/SKILL.md`
|
||||
- Execute to generate task breakdown
|
||||
- Creates: `tasks.md`
|
||||
|
||||
5. **Analyze** (`/speckit.analyze`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.analyze/SKILL.md`
|
||||
5. **Analyze** (`/speckit-analyze`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-analyze/SKILL.md`
|
||||
- Execute to validate consistency across spec, plan, and tasks
|
||||
- Output: Analysis report
|
||||
- **Gate**: If critical issues found, stop and fix before proceeding
|
||||
|
||||
## Implementation Phase (Steps 6-7)
|
||||
|
||||
6. **Implement** (`/speckit.implement`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.implement/SKILL.md`
|
||||
6. **Implement** (`/speckit-implement`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-implement/SKILL.md`
|
||||
- Execute all tasks from `tasks.md` with anti-regression protocols
|
||||
- Output: Working implementation
|
||||
|
||||
7. **Check** (`/speckit.checker`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.checker/SKILL.md`
|
||||
7. **Check** (`/speckit-checker`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-checker/SKILL.md`
|
||||
- Run static analysis (linters, type checkers, security scanners)
|
||||
- Output: Checker report
|
||||
|
||||
## Verification Phase (Steps 8-10)
|
||||
|
||||
8. **Test** (`/speckit.tester`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.tester/SKILL.md`
|
||||
8. **Test** (`/speckit-tester`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-tester/SKILL.md`
|
||||
- Run tests with coverage
|
||||
- Output: Test + coverage report
|
||||
|
||||
9. **Review** (`/speckit.reviewer`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.reviewer/SKILL.md`
|
||||
9. **Review** (`/speckit-reviewer`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-reviewer/SKILL.md`
|
||||
- Perform code review
|
||||
- Output: Review report with findings
|
||||
|
||||
10. **Validate** (`/speckit.validate`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit.validate/SKILL.md`
|
||||
10. **Validate** (`/speckit-validate`):
|
||||
- Use the `view_file` tool to read: `.agents/skills/speckit-validate/SKILL.md`
|
||||
- Verify implementation matches spec requirements
|
||||
- Output: Validation report (pass/fail)
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/speckit.all "Build a user authentication system with OAuth2 support"
|
||||
/speckit-all "Build a user authentication system with OAuth2 support"
|
||||
```
|
||||
|
||||
## Pipeline Comparison
|
||||
|
||||
| Pipeline | Steps | Use When |
|
||||
| ------------------ | ------------------------- | -------------------------------------- |
|
||||
| `/speckit.prepare` | 1-5 (Specify → Analyze) | Planning only — you'll implement later |
|
||||
| `/speckit.all` | 1-10 (Specify → Validate) | Full lifecycle in one pass |
|
||||
| `/speckit-prepare` | 1-5 (Specify → Analyze) | Planning only — you'll implement later |
|
||||
| `/speckit-all` | 1-10 (Specify → Validate) | Full lifecycle in one pass |
|
||||
|
||||
## On Error
|
||||
|
||||
@@ -82,4 +82,4 @@ If any step fails, stop the pipeline and report:
|
||||
|
||||
- Which step failed
|
||||
- The error message
|
||||
- Suggested remediation (e.g., "Run `/speckit.clarify` to resolve ambiguities before continuing")
|
||||
- Suggested remediation (e.g., "Run `/speckit-clarify` to resolve ambiguities before continuing")
|
||||
+2
-2
@@ -2,13 +2,13 @@
|
||||
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
|
||||
---
|
||||
|
||||
# Workflow: speckit.constitution
|
||||
# Workflow: speckit-constitution
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.constitution/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-constitution/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
@@ -2,14 +2,14 @@
|
||||
description: Create or update the feature specification from a natural language feature description.
|
||||
---
|
||||
|
||||
# Workflow: speckit.specify
|
||||
# Workflow: speckit-specify
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
- This is typically the starting point of a new feature.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.specify/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-specify/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
@@ -2,17 +2,17 @@
|
||||
description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec.
|
||||
---
|
||||
|
||||
# Workflow: speckit.clarify
|
||||
# Workflow: speckit-clarify
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.clarify/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-clarify/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first to create the feature specification
|
||||
- If `spec.md` is missing: Run `/speckit-specify` first to create the feature specification
|
||||
@@ -2,17 +2,17 @@
|
||||
description: Execute the implementation planning workflow using the plan template to generate design artifacts.
|
||||
---
|
||||
|
||||
# Workflow: speckit.plan
|
||||
# Workflow: speckit-plan
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.plan/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-plan/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first to create the feature specification
|
||||
- If `spec.md` is missing: Run `/speckit-specify` first to create the feature specification
|
||||
@@ -2,18 +2,18 @@
|
||||
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
|
||||
---
|
||||
|
||||
# Workflow: speckit.tasks
|
||||
# Workflow: speckit-tasks
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.tasks/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-tasks/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `plan.md` is missing: Run `/speckit.plan` first
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first
|
||||
- If `plan.md` is missing: Run `/speckit-plan` first
|
||||
- If `spec.md` is missing: Run `/speckit-specify` first
|
||||
@@ -4,19 +4,19 @@ description: Perform a non-destructive cross-artifact consistency and quality an
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.analyze
|
||||
# Workflow: speckit-analyze
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.analyze/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-analyze/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first
|
||||
- If `plan.md` is missing: Run `/speckit.plan` first
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
- If `spec.md` is missing: Run `/speckit-specify` first
|
||||
- If `plan.md` is missing: Run `/speckit-plan` first
|
||||
- If `tasks.md` is missing: Run `/speckit-tasks` first
|
||||
+5
-5
@@ -2,19 +2,19 @@
|
||||
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md
|
||||
---
|
||||
|
||||
# Workflow: speckit.implement
|
||||
# Workflow: speckit-implement
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.implement/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-implement/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
- If `plan.md` is missing: Run `/speckit.plan` first
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first
|
||||
- If `tasks.md` is missing: Run `/speckit-tasks` first
|
||||
- If `plan.md` is missing: Run `/speckit-plan` first
|
||||
- If `spec.md` is missing: Run `/speckit-specify` first
|
||||
@@ -4,13 +4,13 @@ description: Run static analysis tools and aggregate results.
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.checker
|
||||
# Workflow: speckit-checker
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may specify paths to check or run on entire project.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.checker/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-checker/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
@@ -4,13 +4,13 @@ description: Execute tests, measure coverage, and report results.
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.tester
|
||||
# Workflow: speckit-tester
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may specify test paths, options, or just run all tests.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.tester/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-tester/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
@@ -2,13 +2,13 @@
|
||||
description: Perform code review with actionable feedback and suggestions.
|
||||
---
|
||||
|
||||
# Workflow: speckit.reviewer
|
||||
# Workflow: speckit-reviewer
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may specify files to review, "staged" for git staged changes, or "branch" for branch diff.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.reviewer/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-reviewer/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
@@ -2,18 +2,18 @@
|
||||
description: Validate that implementation matches specification requirements.
|
||||
---
|
||||
|
||||
# Workflow: speckit.validate
|
||||
# Workflow: speckit-validate
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.validate/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-validate/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
- If implementation not started: Run `/speckit.implement` first
|
||||
- If `tasks.md` is missing: Run `/speckit-tasks` first
|
||||
- If implementation not started: Run `/speckit-implement` first
|
||||
@@ -2,26 +2,26 @@
|
||||
description: Execute the full preparation pipeline (Specify -> Clarify -> Plan -> Tasks -> Analyze) in sequence.
|
||||
---
|
||||
|
||||
# Workflow: speckit.prepare
|
||||
# Workflow: speckit-prepare
|
||||
|
||||
This workflow orchestrates the sequential execution of the Speckit preparation phase skills (02-06).
|
||||
|
||||
1. **Step 1: Specify (Skill 02)**
|
||||
- Goal: Create or update the `spec.md` based on user input.
|
||||
- Action: Read and execute `.agents/skills/speckit.specify/SKILL.md`.
|
||||
- Action: Read and execute `.agents/skills/speckit-specify/SKILL.md`.
|
||||
|
||||
2. **Step 2: Clarify (Skill 03)**
|
||||
- Goal: Refine the `spec.md` by identifying and resolving ambiguities.
|
||||
- Action: Read and execute `.agents/skills/speckit.clarify/SKILL.md`.
|
||||
- Action: Read and execute `.agents/skills/speckit-clarify/SKILL.md`.
|
||||
|
||||
3. **Step 3: Plan (Skill 04)**
|
||||
- Goal: Generate `plan.md` from the finalized spec.
|
||||
- Action: Read and execute `.agents/skills/speckit.plan/SKILL.md`.
|
||||
- Action: Read and execute `.agents/skills/speckit-plan/SKILL.md`.
|
||||
|
||||
4. **Step 4: Tasks (Skill 05)**
|
||||
- Goal: Generate actionable `tasks.md` from the plan.
|
||||
- Action: Read and execute `.agents/skills/speckit.tasks/SKILL.md`.
|
||||
- Action: Read and execute `.agents/skills/speckit-tasks/SKILL.md`.
|
||||
|
||||
5. **Step 5: Analyze (Skill 06)**
|
||||
- Goal: Validate consistency across all design artifacts (spec, plan, tasks).
|
||||
- Action: Read and execute `.agents/skills/speckit.analyze/SKILL.md`.
|
||||
- Action: Read and execute `.agents/skills/speckit-analyze/SKILL.md`.
|
||||
+3
-3
@@ -2,17 +2,17 @@
|
||||
description: Generate a custom checklist for the current feature based on user requirements.
|
||||
---
|
||||
|
||||
# Workflow: speckit.checklist
|
||||
# Workflow: speckit-checklist
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.checklist/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-checklist/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first to create the feature specification
|
||||
- If `spec.md` is missing: Run `/speckit-specify` first to create the feature specification
|
||||
@@ -2,13 +2,13 @@
|
||||
description: Compare two versions of a spec or plan to highlight changes.
|
||||
---
|
||||
|
||||
# Workflow: speckit.diff
|
||||
# Workflow: speckit-diff
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt (optional file paths or version references).
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.diff/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-diff/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
@@ -16,4 +16,4 @@ description: Compare two versions of a spec or plan to highlight changes.
|
||||
|
||||
4. **On Error**:
|
||||
- If no files to compare: Use current feature's `spec.md` vs git HEAD
|
||||
- If `spec.md` doesn't exist: Run `/speckit.specify` first
|
||||
- If `spec.md` doesn't exist: Run `/speckit-specify` first
|
||||
+2
-2
@@ -2,13 +2,13 @@
|
||||
description: Migrate existing projects into the speckit structure by generating spec.md, plan.md, and tasks.md from existing code.
|
||||
---
|
||||
|
||||
# Workflow: speckit.migrate
|
||||
# Workflow: speckit-migrate
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt (path to analyze, feature name).
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.migrate/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-migrate/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
@@ -4,17 +4,17 @@ description: Challenge the specification with Socratic questioning to identify l
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.quizme
|
||||
# Workflow: speckit-quizme
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.quizme/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-quizme/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If required files don't exist, inform the user which prerequisite workflow to run first (e.g., `/speckit.specify` to create `spec.md`).
|
||||
- If required files don't exist, inform the user which prerequisite workflow to run first (e.g., `/speckit-specify` to create `spec.md`).
|
||||
@@ -4,17 +4,17 @@ description: Display a dashboard showing feature status, completion percentage,
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.status
|
||||
# Workflow: speckit-status
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may optionally specify a feature to focus on.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.status/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-status/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If no features exist: Report "No features found. Run `/speckit.specify` to create your first feature."
|
||||
- If no features exist: Report "No features found. Run `/speckit-specify` to create your first feature."
|
||||
+3
-3
@@ -2,17 +2,17 @@
|
||||
description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts.
|
||||
---
|
||||
|
||||
# Workflow: speckit.taskstoissues
|
||||
# Workflow: speckit-taskstoissues
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit.taskstoissues/SKILL.md`
|
||||
- Use the `view_file` tool to read the skill file at: `.agents/skills/speckit-taskstoissues/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
- If `tasks.md` is missing: Run `/speckit-tasks` first
|
||||
+20
-3
@@ -88,14 +88,31 @@ export class DocumentNumberingController {
|
||||
})
|
||||
@RequirePermission('correspondence.read')
|
||||
async previewNumber(@Body() dto: PreviewNumberDto) {
|
||||
// ADR-019: Resolve UUID→INT for project and organization IDs
|
||||
const resolvedProjectId = await this.numberingService.resolveIdForPreview(
|
||||
'project',
|
||||
dto.projectId
|
||||
);
|
||||
const resolvedOriginatorId =
|
||||
await this.numberingService.resolveIdForPreview(
|
||||
'organization',
|
||||
dto.originatorOrganizationId
|
||||
);
|
||||
const resolvedRecipientId = dto.recipientOrganizationId
|
||||
? await this.numberingService.resolveIdForPreview(
|
||||
'organization',
|
||||
dto.recipientOrganizationId
|
||||
)
|
||||
: undefined;
|
||||
|
||||
return this.numberingService.previewNumber({
|
||||
projectId: dto.projectId,
|
||||
originatorOrganizationId: dto.originatorOrganizationId,
|
||||
projectId: resolvedProjectId,
|
||||
originatorOrganizationId: resolvedOriginatorId,
|
||||
typeId: dto.correspondenceTypeId,
|
||||
subTypeId: dto.subTypeId,
|
||||
rfaTypeId: dto.rfaTypeId,
|
||||
disciplineId: dto.disciplineId,
|
||||
recipientOrganizationId: dto.recipientOrganizationId,
|
||||
recipientOrganizationId: resolvedRecipientId,
|
||||
year: dto.year,
|
||||
customTokens: dto.customTokens,
|
||||
});
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
// File: src/modules/document-numbering/dto/preview-number.dto.ts
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsInt, IsOptional, IsObject } from 'class-validator';
|
||||
import { IsInt, IsNotEmpty, IsOptional, IsObject } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class PreviewNumberDto {
|
||||
@ApiProperty({ description: 'Project ID' })
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
projectId!: number;
|
||||
@ApiProperty({ description: 'Project ID or UUID' })
|
||||
@IsNotEmpty()
|
||||
projectId!: number | string;
|
||||
|
||||
@ApiProperty({ description: 'Originator organization ID' })
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
originatorOrganizationId!: number;
|
||||
@ApiProperty({ description: 'Originator organization ID or UUID' })
|
||||
@IsNotEmpty()
|
||||
originatorOrganizationId!: number | string;
|
||||
|
||||
@ApiProperty({ description: 'Correspondence type ID' })
|
||||
@IsInt()
|
||||
@@ -43,11 +41,9 @@ export class PreviewNumberDto {
|
||||
@Type(() => Number)
|
||||
year?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Recipient organization ID' })
|
||||
@ApiPropertyOptional({ description: 'Recipient organization ID or UUID' })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
recipientOrganizationId?: number;
|
||||
recipientOrganizationId?: number | string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Custom tokens' })
|
||||
@IsOptional()
|
||||
|
||||
@@ -26,6 +26,7 @@ import { GenerateNumberContext } from '../interfaces/document-numbering.interfac
|
||||
import { ReserveNumberDto } from '../dto/reserve-number.dto';
|
||||
import { ConfirmReservationDto } from '../dto/confirm-reservation.dto';
|
||||
import { Project } from '../../project/entities/project.entity';
|
||||
import { Organization } from '../../organization/entities/organization.entity';
|
||||
|
||||
@Injectable()
|
||||
export class DocumentNumberingService {
|
||||
@@ -66,6 +67,33 @@ export class DocumentNumberingService {
|
||||
return project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADR-019: Public facade for controllers to resolve project/organization IDs
|
||||
*/
|
||||
async resolveIdForPreview(
|
||||
type: 'project' | 'organization',
|
||||
id: number | string
|
||||
): Promise<number> {
|
||||
if (type === 'project') return this.resolveProjectId(id);
|
||||
return this.resolveOrganizationId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve organizationId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveOrganizationId(orgId: number | string): Promise<number> {
|
||||
if (typeof orgId === 'number') return orgId;
|
||||
const num = Number(orgId);
|
||||
if (!isNaN(num)) return num;
|
||||
const org = await this.entityManager.findOne(Organization, {
|
||||
where: { uuid: orgId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!org)
|
||||
throw new NotFoundException(`Organization with UUID ${orgId} not found`);
|
||||
return org.id;
|
||||
}
|
||||
|
||||
async generateNextNumber(
|
||||
ctx: GenerateNumberContext
|
||||
): Promise<{ number: string; auditId: number }> {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { AsBuiltDrawingRevision } from './entities/asbuilt-drawing-revision.enti
|
||||
import { ShopDrawingRevision } from './entities/shop-drawing-revision.entity';
|
||||
import { Attachment } from '../../common/file-storage/entities/attachment.entity';
|
||||
import { User } from '../user/entities/user.entity';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
|
||||
// DTOs
|
||||
import { CreateAsBuiltDrawingDto } from './dto/create-asbuilt-drawing.dto';
|
||||
@@ -39,6 +40,22 @@ export class AsBuiltDrawingService {
|
||||
private dataSource: DataSource
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve projectId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
const project = await this.dataSource.manager.findOne(Project, {
|
||||
where: { uuid: projectId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!project)
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
return project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* สร้าง AS Built Drawing ใหม่ พร้อม Revision แรก (Rev 0)
|
||||
*/
|
||||
@@ -73,9 +90,14 @@ export class AsBuiltDrawingService {
|
||||
});
|
||||
}
|
||||
|
||||
// ADR-019: Resolve UUID→INT
|
||||
const internalProjectId = await this.resolveProjectId(
|
||||
createDto.projectId
|
||||
);
|
||||
|
||||
// 3. Create Master AS Built Drawing
|
||||
const asBuiltDrawing = queryRunner.manager.create(AsBuiltDrawing, {
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
drawingNumber: createDto.drawingNumber,
|
||||
mainCategoryId: createDto.mainCategoryId,
|
||||
subCategoryId: createDto.subCategoryId,
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ContractDrawing } from './entities/contract-drawing.entity';
|
||||
import { Attachment } from '../../common/file-storage/entities/attachment.entity';
|
||||
import { User } from '../user/entities/user.entity';
|
||||
import { Contract } from '../contract/entities/contract.entity';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
|
||||
// DTOs
|
||||
import { CreateContractDrawingDto } from './dto/create-contract-drawing.dto';
|
||||
@@ -36,6 +37,22 @@ export class ContractDrawingService {
|
||||
private dataSource: DataSource
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve projectId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
const project = await this.dataSource.manager.findOne(Project, {
|
||||
where: { uuid: projectId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!project)
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
return project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve issueDate from contract.startDate for file storage path
|
||||
* Fallback: contract.startDate → current date
|
||||
@@ -54,10 +71,13 @@ export class ContractDrawingService {
|
||||
* - ผูกไฟล์แนบและ Commit ไฟล์จาก Temp -> Permanent
|
||||
*/
|
||||
async create(createDto: CreateContractDrawingDto, user: User) {
|
||||
// ADR-019: Resolve UUID→INT for projectId
|
||||
const internalProjectId = await this.resolveProjectId(createDto.projectId);
|
||||
|
||||
// 1. ตรวจสอบเลขที่แบบซ้ำ (Unique per Project)
|
||||
const exists = await this.drawingRepo.findOne({
|
||||
where: {
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
contractDrawingNo: createDto.contractDrawingNo,
|
||||
},
|
||||
});
|
||||
@@ -83,7 +103,7 @@ export class ContractDrawingService {
|
||||
|
||||
// 3. สร้าง Entity
|
||||
const drawing = queryRunner.manager.create(ContractDrawing, {
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
contractDrawingNo: createDto.contractDrawingNo,
|
||||
title: createDto.title,
|
||||
mapCatId: createDto.mapCatId, // Updated
|
||||
@@ -98,9 +118,8 @@ export class ContractDrawingService {
|
||||
// 4. Commit Files (ย้ายไฟล์จริง)
|
||||
if (createDto.attachmentIds?.length) {
|
||||
// ✅ FIX TS2345: แปลง number[] เป็น string[] ก่อนส่ง
|
||||
const issueDate = await this.resolveIssueDateByProject(
|
||||
createDto.projectId
|
||||
);
|
||||
const issueDate =
|
||||
await this.resolveIssueDateByProject(internalProjectId);
|
||||
await this.fileStorageService.commit(
|
||||
createDto.attachmentIds.map(String),
|
||||
{ issueDate, documentType: 'ContractDrawing' }
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ShopDrawingRevision } from './entities/shop-drawing-revision.entity';
|
||||
import { ContractDrawing } from './entities/contract-drawing.entity';
|
||||
import { Attachment } from '../../common/file-storage/entities/attachment.entity';
|
||||
import { User } from '../user/entities/user.entity';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
|
||||
// DTOs
|
||||
import { CreateShopDrawingDto } from './dto/create-shop-drawing.dto';
|
||||
@@ -39,6 +40,22 @@ export class ShopDrawingService {
|
||||
private dataSource: DataSource
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve projectId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
const project = await this.dataSource.manager.findOne(Project, {
|
||||
where: { uuid: projectId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!project)
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
return project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* สร้าง Shop Drawing ใหม่ พร้อม Revision แรก (Rev 0)
|
||||
*/
|
||||
@@ -73,9 +90,14 @@ export class ShopDrawingService {
|
||||
});
|
||||
}
|
||||
|
||||
// ADR-019: Resolve UUID→INT
|
||||
const internalProjectId = await this.resolveProjectId(
|
||||
createDto.projectId
|
||||
);
|
||||
|
||||
// 3. Create Master Shop Drawing
|
||||
const shopDrawing = queryRunner.manager.create(ShopDrawing, {
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
drawingNumber: createDto.drawingNumber,
|
||||
mainCategoryId: createDto.mainCategoryId,
|
||||
subCategoryId: createDto.subCategoryId,
|
||||
|
||||
@@ -11,10 +11,18 @@ import {
|
||||
} from 'class-validator';
|
||||
|
||||
export class CreateRfaDto {
|
||||
@ApiProperty({ description: 'ID ของโครงการ', example: 1 })
|
||||
@IsInt()
|
||||
@ApiProperty({ description: 'ID or UUID ของโครงการ', example: 1 })
|
||||
@IsNotEmpty()
|
||||
projectId!: number;
|
||||
projectId!: number | string;
|
||||
|
||||
@ApiProperty({ description: 'Contract ID or UUID', required: false })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
contractId?: string;
|
||||
|
||||
@ApiProperty({ description: 'To Organization ID or UUID', required: false })
|
||||
@IsOptional()
|
||||
toOrganizationId?: number | string;
|
||||
|
||||
@ApiProperty({ description: 'ID ของประเภท RFA', example: 1 })
|
||||
@IsInt()
|
||||
|
||||
@@ -12,6 +12,8 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DataSource, In, Repository } from 'typeorm';
|
||||
|
||||
// Entities
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
import { Organization } from '../organization/entities/organization.entity';
|
||||
import { CorrespondenceRouting } from '../correspondence/entities/correspondence-routing.entity';
|
||||
import { Correspondence } from '../correspondence/entities/correspondence.entity';
|
||||
import { CorrespondenceRevision } from '../correspondence/entities/correspondence-revision.entity';
|
||||
@@ -81,7 +83,42 @@ export class RfaService {
|
||||
private searchService: SearchService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve projectId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
const project = await this.dataSource.manager.findOne(Project, {
|
||||
where: { uuid: projectId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!project)
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
return project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve organizationId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveOrganizationId(orgId: number | string): Promise<number> {
|
||||
if (typeof orgId === 'number') return orgId;
|
||||
const num = Number(orgId);
|
||||
if (!isNaN(num)) return num;
|
||||
const org = await this.dataSource.manager.findOne(Organization, {
|
||||
where: { uuid: orgId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!org)
|
||||
throw new NotFoundException(`Organization with UUID ${orgId} not found`);
|
||||
return org.id;
|
||||
}
|
||||
|
||||
async create(createDto: CreateRfaDto, user: User) {
|
||||
// ADR-019: Resolve UUID→INT for projectId
|
||||
const internalProjectId = await this.resolveProjectId(createDto.projectId);
|
||||
|
||||
const rfaType = await this.rfaTypeRepo.findOne({
|
||||
where: { id: createDto.rfaTypeId },
|
||||
});
|
||||
@@ -115,7 +152,7 @@ export class RfaService {
|
||||
|
||||
// [UPDATED] Generate Document Number with Discipline
|
||||
const docNumber = await this.numberingService.generateNextNumber({
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
originatorOrganizationId: userOrgId,
|
||||
typeId: createDto.rfaTypeId,
|
||||
disciplineId: createDto.disciplineId ?? 0, // ✅ ส่ง disciplineId ไปด้วย (0 ถ้าไม่มี)
|
||||
@@ -142,7 +179,7 @@ export class RfaService {
|
||||
const correspondence = queryRunner.manager.create(Correspondence, {
|
||||
correspondenceNumber: docNumber.number,
|
||||
correspondenceTypeId: createDto.rfaTypeId,
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
originatorId: userOrgId,
|
||||
isInternal: false,
|
||||
createdBy: user.user_id,
|
||||
@@ -219,7 +256,7 @@ export class RfaService {
|
||||
'rfa',
|
||||
savedRfa.id.toString(),
|
||||
{
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
originatorId: userOrgId,
|
||||
disciplineId: createDto.disciplineId,
|
||||
initiatorId: user.user_id,
|
||||
@@ -240,7 +277,7 @@ export class RfaService {
|
||||
title: createDto.subject,
|
||||
description: createDto.description,
|
||||
status: 'DRAFT',
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
createdAt: new Date(),
|
||||
})
|
||||
.catch((err) => this.logger.error(`Indexing failed: ${err}`));
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Correspondence } from '../correspondence/entities/correspondence.entity
|
||||
import { CorrespondenceRevision } from '../correspondence/entities/correspondence-revision.entity';
|
||||
import { CorrespondenceType } from '../correspondence/entities/correspondence-type.entity';
|
||||
import { CorrespondenceStatus } from '../correspondence/entities/correspondence-status.entity';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
|
||||
@Injectable()
|
||||
export class TransmittalService {
|
||||
@@ -34,6 +35,22 @@ export class TransmittalService {
|
||||
private dataSource: DataSource
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve projectId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
const project = await this.dataSource.manager.findOne(Project, {
|
||||
where: { uuid: projectId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!project)
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
return project.id;
|
||||
}
|
||||
|
||||
async create(createDto: CreateTransmittalDto, user: User) {
|
||||
// 1. Get Transmittal Type (Assuming Code '901' or 'TRN')
|
||||
const type = await this.typeRepo.findOne({
|
||||
@@ -58,9 +75,14 @@ export class TransmittalService {
|
||||
}
|
||||
|
||||
try {
|
||||
// ADR-019: Resolve UUID→INT for projectId
|
||||
const internalProjectId = await this.resolveProjectId(
|
||||
createDto.projectId
|
||||
);
|
||||
|
||||
// 2. Generate Number
|
||||
const docNumber = await this.numberingService.generateNextNumber({
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
originatorOrganizationId: user.primaryOrganizationId,
|
||||
typeId: type.id,
|
||||
year: new Date().getFullYear(),
|
||||
@@ -74,7 +96,7 @@ export class TransmittalService {
|
||||
const correspondence = queryRunner.manager.create(Correspondence, {
|
||||
correspondenceNumber: docNumber.number,
|
||||
correspondenceTypeId: type.id,
|
||||
projectId: createDto.projectId,
|
||||
projectId: internalProjectId,
|
||||
originatorId: user.primaryOrganizationId,
|
||||
isInternal: false,
|
||||
createdBy: user.user_id,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
MinLength,
|
||||
IsOptional,
|
||||
IsBoolean,
|
||||
IsInt,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
@@ -44,10 +43,12 @@ export class CreateUserDto {
|
||||
@IsOptional()
|
||||
lineId?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Primary Organization ID', example: 1 })
|
||||
@IsInt()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Primary Organization ID or UUID',
|
||||
example: 1,
|
||||
})
|
||||
@IsOptional()
|
||||
primaryOrganizationId?: number; // รับเป็น ID ของ Organization
|
||||
primaryOrganizationId?: number | string; // ADR-019: Accept INT or UUID
|
||||
|
||||
@ApiPropertyOptional({ description: 'Is user active?', default: true })
|
||||
@IsBoolean()
|
||||
|
||||
@@ -16,11 +16,9 @@ export class SearchUserDto {
|
||||
@Type(() => Number)
|
||||
roleId?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Filter by Organization ID' })
|
||||
@ApiPropertyOptional({ description: 'Filter by Organization ID or UUID' })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
primaryOrganizationId?: number;
|
||||
primaryOrganizationId?: number | string; // ADR-019: Accept INT or UUID
|
||||
|
||||
@ApiPropertyOptional({ description: 'Page number', default: 1 })
|
||||
@IsOptional()
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Role } from './entities/role.entity';
|
||||
import { Permission } from './entities/permission.entity';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
import { Organization } from '../organization/entities/organization.entity';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
@@ -30,13 +31,35 @@ export class UserService {
|
||||
@Inject(CACHE_MANAGER) private cacheManager: Cache
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve organizationId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveOrganizationId(orgId: number | string): Promise<number> {
|
||||
if (typeof orgId === 'number') return orgId;
|
||||
const num = Number(orgId);
|
||||
if (!isNaN(num)) return num;
|
||||
const org = await this.usersRepository.manager.findOne(Organization, {
|
||||
where: { uuid: orgId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!org)
|
||||
throw new NotFoundException(`Organization with UUID ${orgId} not found`);
|
||||
return org.id;
|
||||
}
|
||||
|
||||
// 1. สร้างผู้ใช้ (Hash Password ก่อนบันทึก)
|
||||
async create(createUserDto: CreateUserDto): Promise<User> {
|
||||
const salt = await bcrypt.genSalt();
|
||||
const hashedPassword = await bcrypt.hash(createUserDto.password, salt);
|
||||
|
||||
// ADR-019: Resolve UUID→INT for primaryOrganizationId
|
||||
const resolvedOrgId = createUserDto.primaryOrganizationId
|
||||
? await this.resolveOrganizationId(createUserDto.primaryOrganizationId)
|
||||
: undefined;
|
||||
|
||||
const newUser = this.usersRepository.create({
|
||||
...createUserDto,
|
||||
primaryOrganizationId: resolvedOrgId,
|
||||
password: hashedPassword,
|
||||
});
|
||||
|
||||
@@ -91,8 +114,12 @@ export class UserService {
|
||||
}
|
||||
|
||||
if (primaryOrganizationId) {
|
||||
// ADR-019: Resolve UUID→INT for filtering
|
||||
const resolvedOrgId = await this.resolveOrganizationId(
|
||||
primaryOrganizationId
|
||||
);
|
||||
query.andWhere('user.primaryOrganizationId = :orgId', {
|
||||
orgId: primaryOrganizationId,
|
||||
orgId: resolvedOrgId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -164,7 +191,18 @@ export class UserService {
|
||||
updateUserDto.password = await bcrypt.hash(updateUserDto.password, salt);
|
||||
}
|
||||
|
||||
const updatedUser = this.usersRepository.merge(user, updateUserDto);
|
||||
// ADR-019: Resolve UUID→INT for primaryOrganizationId before merge
|
||||
const resolvedDto: Record<string, unknown> = { ...updateUserDto };
|
||||
if (updateUserDto.primaryOrganizationId !== undefined) {
|
||||
resolvedDto.primaryOrganizationId = await this.resolveOrganizationId(
|
||||
updateUserDto.primaryOrganizationId
|
||||
);
|
||||
}
|
||||
|
||||
const updatedUser = this.usersRepository.merge(
|
||||
user,
|
||||
resolvedDto as Partial<User>
|
||||
);
|
||||
const savedUser = await this.usersRepository.save(updatedUser);
|
||||
|
||||
// ⚠️ สำคัญ: เมื่อมีการแก้ไขข้อมูล User ต้องเคลียร์ Cache สิทธิ์เสมอ
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function UsersPage() {
|
||||
|
||||
const { data: users, isLoading } = useUsers({
|
||||
search: search || undefined,
|
||||
primaryOrganizationId: selectedOrgId ? parseInt(selectedOrgId) : undefined,
|
||||
primaryOrganizationId: selectedOrgId ?? undefined,
|
||||
});
|
||||
|
||||
const { data: organizations = [] } = useOrganizations();
|
||||
@@ -94,7 +94,7 @@ export default function UsersPage() {
|
||||
header: "Organization",
|
||||
cell: ({ row }) => {
|
||||
const orgId = row.original.primaryOrganizationId;
|
||||
const org = (organizations as Organization[]).find((o) => o.id === orgId);
|
||||
const org = (organizations as Organization[]).find((o) => (o.id ?? o.uuid) === orgId?.toString() || o.uuid === orgId?.toString());
|
||||
return org ? org.organizationCode : "-";
|
||||
},
|
||||
},
|
||||
@@ -186,7 +186,7 @@ export default function UsersPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Organizations</SelectItem>
|
||||
{Array.isArray(organizations) && (organizations as Organization[]).map((org) => (
|
||||
<SelectItem key={org.uuid} value={(org.id ?? org.uuid).toString()}>
|
||||
<SelectItem key={org.uuid} value={org.uuid}>
|
||||
{org.organizationCode} - {org.organizationName}
|
||||
</SelectItem>
|
||||
))}
|
||||
|
||||
@@ -14,7 +14,7 @@ function RFAsContent() {
|
||||
const page = parseInt(searchParams.get('page') || '1');
|
||||
const statusId = searchParams.get('status') ? parseInt(searchParams.get('status')!) : undefined;
|
||||
const search = searchParams.get('search') || undefined;
|
||||
const projectId = searchParams.get('projectId') ? parseInt(searchParams.get('projectId')!) : undefined;
|
||||
const projectId = searchParams.get('projectId') || undefined; // ADR-019: Pass UUID string directly
|
||||
|
||||
const revisionStatus = (searchParams.get('revisionStatus') as 'CURRENT' | 'ALL' | 'OLD') || 'CURRENT';
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ const userSchema = z.object({
|
||||
confirmPassword: z.string().optional(),
|
||||
isActive: z.boolean().optional(),
|
||||
lineId: z.string().optional(),
|
||||
primaryOrganizationId: z.number().optional(),
|
||||
primaryOrganizationId: z.string().optional(),
|
||||
roleIds: z.array(z.number()).optional(),
|
||||
}).refine((data) => {
|
||||
// If password is provided (creating or resetting), confirmPassword must match
|
||||
@@ -107,7 +107,7 @@ export function UserDialog({ open, onOpenChange, user }: UserDialogProps) {
|
||||
lastName: user.lastName,
|
||||
isActive: user.isActive,
|
||||
lineId: user.lineId || "",
|
||||
primaryOrganizationId: user.primaryOrganizationId,
|
||||
primaryOrganizationId: user.primaryOrganizationId?.toString(),
|
||||
roleIds: user.roles?.map((r: any) => r.roleId) || [],
|
||||
password: "",
|
||||
confirmPassword: ""
|
||||
@@ -221,22 +221,19 @@ export function UserDialog({ open, onOpenChange, user }: UserDialogProps) {
|
||||
<div>
|
||||
<Label>Primary Organization</Label>
|
||||
<Select
|
||||
value={watch("primaryOrganizationId")?.toString()}
|
||||
value={watch("primaryOrganizationId") ?? undefined}
|
||||
onValueChange={(val) =>
|
||||
setValue("primaryOrganizationId", parseInt(val))
|
||||
setValue("primaryOrganizationId", val)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select Organization" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{/* TODO: ADR-019 — Backend DTO needs to accept UUID for primaryOrganization.
|
||||
Currently using org.id which is excluded from API responses.
|
||||
Temporary: org.id may still exist in some query responses. */}
|
||||
{organizations?.map((org: any) => (
|
||||
<SelectItem
|
||||
key={org.uuid ?? org.id}
|
||||
value={(org.id ?? 0).toString()}
|
||||
key={org.uuid}
|
||||
value={org.uuid}
|
||||
>
|
||||
{org.organizationCode} - {org.organizationName}
|
||||
</SelectItem>
|
||||
|
||||
@@ -80,7 +80,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
|
||||
const router = useRouter();
|
||||
|
||||
// Hooks
|
||||
const { data: contractCategories } = useContractDrawingCategories();
|
||||
const { data: contractCategories } = useContractDrawingCategories(projectId);
|
||||
const { data: shopMainCats } = useShopMainCategories(projectId);
|
||||
|
||||
const [selectedShopMainCat, setSelectedShopMainCat] = useState<number | undefined>();
|
||||
@@ -202,7 +202,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{contractCategories?.map((c: any) => (
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.catName || c.catCode || c.name}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
@@ -253,7 +253,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{shopMainCats?.map((c: any) => (
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.mainCategoryName || c.mainCategoryCode || c.name}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
@@ -269,7 +269,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{shopSubCats?.map((c: any) => (
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.subCategoryName || c.subCategoryCode || c.name}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
@@ -323,7 +323,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{shopMainCats?.map((c: any) => (
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.mainCategoryName || c.mainCategoryCode || c.name}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
@@ -339,7 +339,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{shopSubCats?.map((c: any) => (
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
|
||||
<SelectItem key={c.id} value={String(c.id)}>{c.subCategoryName || c.subCategoryCode || c.name}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
@@ -37,7 +37,7 @@ const VARIABLES = [
|
||||
|
||||
export interface TemplateEditorProps {
|
||||
template?: NumberingTemplate;
|
||||
projectId: number;
|
||||
projectId: number | string;
|
||||
projectName: string;
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
correspondenceTypes: any[];
|
||||
|
||||
@@ -30,14 +30,14 @@ const rfaItemSchema = z.object({
|
||||
unit: z.string().min(1, "Unit is required"),
|
||||
});
|
||||
const rfaSchema = z.object({
|
||||
contractId: z.number().min(1, "Contract is required"),
|
||||
contractId: z.string().min(1, "Contract is required"),
|
||||
disciplineId: z.number().min(1, "Discipline is required"),
|
||||
rfaTypeId: z.number().min(1, "Type is required"),
|
||||
subject: z.string().min(5, "Subject must be at least 5 characters"),
|
||||
description: z.string().optional(),
|
||||
body: z.string().optional(),
|
||||
remarks: z.string().optional(),
|
||||
toOrganizationId: z.number().min(1, "Please select To Organization"),
|
||||
toOrganizationId: z.string().min(1, "Please select To Organization"),
|
||||
dueDate: z.string().optional(),
|
||||
shopDrawingRevisionIds: z.array(z.number()).optional(),
|
||||
items: z.array(rfaItemSchema).min(1, "At least one item is required"),
|
||||
@@ -63,14 +63,14 @@ export function RFAForm() {
|
||||
} = useForm<RFAFormData>({
|
||||
resolver: zodResolver(rfaSchema),
|
||||
defaultValues: {
|
||||
contractId: 0,
|
||||
contractId: "",
|
||||
disciplineId: 0,
|
||||
rfaTypeId: 0,
|
||||
subject: "",
|
||||
description: "",
|
||||
body: "",
|
||||
remarks: "",
|
||||
toOrganizationId: 0,
|
||||
toOrganizationId: "",
|
||||
dueDate: "",
|
||||
shopDrawingRevisionIds: [],
|
||||
items: [{ itemNo: "1", description: "", quantity: 0, unit: "" }],
|
||||
@@ -182,7 +182,7 @@ export function RFAForm() {
|
||||
<div>
|
||||
<Label>Contract *</Label>
|
||||
<Select
|
||||
onValueChange={(val) => setValue("contractId", Number(val))}
|
||||
onValueChange={(val) => setValue("contractId", val)}
|
||||
disabled={isLoadingContracts}
|
||||
>
|
||||
<SelectTrigger>
|
||||
@@ -190,8 +190,8 @@ export function RFAForm() {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{contracts?.map((c: any) => (
|
||||
<SelectItem key={c.id || c.contract_id} value={String(c.id || c.contract_id)}>
|
||||
{c.name || c.contract_no}
|
||||
<SelectItem key={c.id} value={String(c.id)}>
|
||||
{c.contractName || c.name || c.contractCode}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -59,7 +59,7 @@ const itemSchema = z.object({
|
||||
|
||||
// Main form schema
|
||||
const formSchema = z.object({
|
||||
correspondenceId: z.number().min(1, "Correspondence is required"), // Linked correspondence (e.g. Originator Letter)
|
||||
correspondenceId: z.string().min(1, "Correspondence is required"), // ADR-019: UUID string
|
||||
subject: z.string().min(1, "Subject is required"),
|
||||
purpose: z.enum(["FOR_APPROVAL", "FOR_INFORMATION", "FOR_REVIEW", "OTHER"]),
|
||||
remarks: z.string().optional(),
|
||||
@@ -127,7 +127,7 @@ export function TransmittalForm() {
|
||||
|
||||
const selectedDocId = form.watch("correspondenceId");
|
||||
const selectedDoc = correspondences?.data?.find(
|
||||
(c: { id: number }) => c.id === selectedDocId
|
||||
(c: { uuid: string }) => c.uuid === selectedDocId
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -172,19 +172,19 @@ export function TransmittalForm() {
|
||||
<CommandEmpty>No document found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{correspondences?.data?.map(
|
||||
(doc: { id: number; correspondence_number: string }) => (
|
||||
(doc: { uuid: string; correspondence_number: string }) => (
|
||||
<CommandItem
|
||||
key={doc.id}
|
||||
key={doc.uuid}
|
||||
value={doc.correspondence_number}
|
||||
onSelect={() => {
|
||||
form.setValue("correspondenceId", doc.id);
|
||||
form.setValue("correspondenceId", doc.uuid);
|
||||
setDocOpen(false);
|
||||
}}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
doc.id === field.value
|
||||
doc.uuid === field.value
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
|
||||
@@ -104,10 +104,11 @@ export function useCorrespondenceTypes() {
|
||||
|
||||
// --- Drawing Categories Hooks ---
|
||||
|
||||
export function useContractDrawingCategories() {
|
||||
export function useContractDrawingCategories(projectId?: number | string) {
|
||||
return useQuery({
|
||||
queryKey: ['contract-drawing-categories'],
|
||||
queryFn: () => masterDataService.getContractDrawingCategories(),
|
||||
queryKey: ['contract-drawing-categories', projectId],
|
||||
queryFn: () => masterDataService.getContractDrawingCategories(projectId),
|
||||
enabled: !!projectId,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import apiClient from '@/lib/api/client';
|
||||
*/
|
||||
export interface NumberingTemplate {
|
||||
id: number;
|
||||
projectId: number;
|
||||
projectId: number | string;
|
||||
correspondenceTypeId: number | null; // null = Default Format for project
|
||||
correspondenceType?: {
|
||||
id: number;
|
||||
@@ -18,9 +18,10 @@ export interface NumberingTemplate {
|
||||
typeName: string;
|
||||
} | null;
|
||||
project?: {
|
||||
id: number;
|
||||
id: number | string;
|
||||
projectCode: string;
|
||||
projectName: string;
|
||||
uuid?: string;
|
||||
};
|
||||
formatTemplate: string;
|
||||
description?: string;
|
||||
|
||||
@@ -187,8 +187,10 @@ export const masterDataService = {
|
||||
|
||||
// --- Drawing Categories ---
|
||||
|
||||
getContractDrawingCategories: async () => {
|
||||
const response = await apiClient.get("/drawings/contract/categories");
|
||||
getContractDrawingCategories: async (projectId?: number | string) => {
|
||||
const response = await apiClient.get("/drawings/contract/categories", {
|
||||
params: { projectId }
|
||||
});
|
||||
return response.data.data || response.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ const mapWorkflow = (backendObj: any): Workflow => {
|
||||
workflowId: backendObj.id,
|
||||
workflowName: backendObj.dsl?.workflowName || backendObj.workflow_code,
|
||||
description: backendObj.description || backendObj.dsl?.description || '',
|
||||
workflowType: backendObj.workflow_code,
|
||||
workflowType: backendObj.workflow_code?.toUpperCase() || backendObj.workflow_code,
|
||||
version: backendObj.version || 1,
|
||||
isActive: backendObj.is_active,
|
||||
dslDefinition: typeof backendObj.dsl === 'string' ? backendObj.dsl : backendObj.dsl?.dslDefinition || JSON.stringify(backendObj.dsl, null, 2),
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
// --- Create ---
|
||||
export interface CreateRfaDto {
|
||||
/** ID ของโครงการ */
|
||||
projectId: number;
|
||||
/** ID or UUID ของโครงการ */
|
||||
projectId: number | string; // ADR-019: Accept UUID
|
||||
|
||||
/** ประเภท RFA (เช่น DWG, MAT) */
|
||||
rfaTypeId: number;
|
||||
@@ -20,8 +20,11 @@ export interface CreateRfaDto {
|
||||
/** หมายเหตุ */
|
||||
remarks?: string;
|
||||
|
||||
/** Contract UUID (optional) */
|
||||
contractId?: string; // ADR-019: Contract UUID
|
||||
|
||||
/** ส่งถึงใคร (สำหรับ Routing Step 1) */
|
||||
toOrganizationId: number;
|
||||
toOrganizationId: number | string; // ADR-019: Accept UUID
|
||||
|
||||
/** รายละเอียดเพิ่มเติม */
|
||||
description?: string;
|
||||
@@ -41,8 +44,8 @@ export type UpdateRfaDto = Partial<CreateRfaDto>;
|
||||
|
||||
// --- Search ---
|
||||
export interface SearchRfaDto {
|
||||
/** Filter by Project ID (optional to allow cross-project search) */
|
||||
projectId?: number;
|
||||
/** Filter by Project ID or UUID (optional to allow cross-project search) */
|
||||
projectId?: number | string; // ADR-019: Accept UUID
|
||||
|
||||
/** กรองตามประเภท RFA */
|
||||
rfaTypeId?: number;
|
||||
|
||||
@@ -9,12 +9,12 @@ export enum TransmittalPurpose {
|
||||
|
||||
// --- Create ---
|
||||
export interface CreateTransmittalDto {
|
||||
projectId?: number;
|
||||
recipientOrganizationId?: number;
|
||||
projectId?: number | string; // ADR-019: Accept UUID
|
||||
recipientOrganizationId?: number | string; // ADR-019: Accept UUID
|
||||
subject: string;
|
||||
purpose?: string;
|
||||
remarks?: string;
|
||||
correspondenceId: number; // For now linked correspondence
|
||||
correspondenceId: number | string; // ADR-019: Accept UUID
|
||||
items: CreateTransmittalItemDto[];
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export type UpdateTransmittalDto = Partial<CreateTransmittalDto>;
|
||||
// --- Search ---
|
||||
export interface SearchTransmittalDto {
|
||||
/** บังคับระบุ Project */
|
||||
projectId: number;
|
||||
projectId: number | string; // ADR-019: Accept UUID
|
||||
|
||||
purpose?: TransmittalPurpose;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface CreateUserDto {
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
lineId?: string;
|
||||
primaryOrganizationId?: number;
|
||||
primaryOrganizationId?: number | string; // ADR-019: Accept UUID
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,9 @@ export interface RFA {
|
||||
}
|
||||
|
||||
export interface CreateRFADto {
|
||||
projectId: number;
|
||||
projectId: number | string; // ADR-019: Accept UUID
|
||||
contractId?: string; // ADR-019: Contract UUID
|
||||
toOrganizationId?: number | string; // ADR-019: Recipient org UUID
|
||||
rfaTypeId: number;
|
||||
disciplineId?: number;
|
||||
subject: string;
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface User {
|
||||
lastName: string;
|
||||
isActive: boolean;
|
||||
lineId?: string;
|
||||
primaryOrganizationId?: number;
|
||||
primaryOrganizationId?: number | string; // ADR-019: May be INT or UUID
|
||||
organization?: UserOrganization;
|
||||
roles?: Role[];
|
||||
|
||||
@@ -42,7 +42,7 @@ export interface CreateUserDto {
|
||||
password?: string;
|
||||
isActive: boolean;
|
||||
lineId?: string;
|
||||
primaryOrganizationId?: number;
|
||||
primaryOrganizationId?: number | string; // ADR-019: Accept UUID
|
||||
roleIds: number[];
|
||||
}
|
||||
|
||||
@@ -53,5 +53,5 @@ export interface SearchUserDto {
|
||||
limit?: number;
|
||||
search?: string;
|
||||
roleId?: number;
|
||||
primaryOrganizationId?: number;
|
||||
primaryOrganizationId?: number | string; // ADR-019: Accept UUID
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user