260224:1606 20260224:1600 V1.8.0
All checks were successful
Build and Deploy / deploy (push) Successful in 6m25s

This commit is contained in:
admin
2026-02-24 16:06:15 +07:00
parent 97cc41f489
commit 158179d4a5
255 changed files with 5339 additions and 2094 deletions

View File

@@ -4,64 +4,72 @@ trigger: always_on
# Project Specifications & Context Protocol
Description: Enforces strict adherence to the project's documentation structure (specs/00-06) for all agent activities.
Globs: *
Description: Enforces strict adherence to the project's documentation structure for all agent activities.
Globs: \*
---
## Agent Role
You are a Principal Engineer and Architect strictly bound by the project's documentation. You do not improvise outside of the defined specifications.
## The Context Loading Protocol
Before generating code or planning a solution, you MUST conceptually load the context in this specific order:
1. **🎯 ACTIVE TASK (`specs/06-tasks/`)**
- Identify the current active task file.
- *Action:* Determine the immediate scope. Do NOT implement features not listed here.
1. **📖 PROJECT CONTEXT (`specs/00-Overview/`)**
- _Action:_ Align with the high-level goals and domain language described here.
2. **📖 PROJECT CONTEXT (`specs/00-overview/`)**
- *Action:* Align with the high-level goals and domain language described here.
2. **✅ REQUIREMENTS (`specs/01-Requirements/`)**
- _Action:_ Verify that your plan satisfies the functional requirements and user stories.
- _Constraint:_ If a requirement is ambiguous, stop and ask.
3. **✅ REQUIREMENTS (`specs/01-requirements/`)**
- *Action:* Verify that your plan satisfies the functional requirements and user stories.
- *Constraint:* If a requirement is ambiguous, stop and ask.
3. **🏗 ARCHITECTURE & DECISIONS (`specs/02-Architecture/` & `specs/06-Decision-Records/`)**
- _Action:_ Adhere to the defined system design.
- _Crucial:_ Check `specs/06-Decision-Records/` (ADRs) to ensure you do not violate previously agreed-upon technical decisions.
4. **🏗 ARCHITECTURE & DECISIONS (`specs/02-architecture/` & `specs/05-decisions/`)**
- *Action:* Adhere to the defined system design.
- *Crucial:* Check `specs/05-decisions/` (ADRs) to ensure you do not violate previously agreed-upon technical decisions.
4. **💾 DATABASE & SCHEMA (`specs/03-Data-and-Storage/`)**
- _Action:_
- **Read `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`** for exact table structures and constraints.
- **Consult `specs/03-Data-and-Storage/03-01-data-dictionary.md`** for field meanings and business rules.
- **Check `specs/03-Data-and-Storage/lcbp3-v1.7.0-seed-basic.sql`** to understand initial data states.
- **Check `specs/03-Data-and-Storage/lcbp3-v1.7.0-seed-permissions.sql`** to understand initial permissions states.
- _Constraint:_ NEVER invent table names or columns. Use ONLY what is defined here.
5. **💾 DATABASE & SCHEMA (`specs/07-database/`)**
- *Action:* - **Read `specs/07-database/lcbp3-v1.7.0-schema.sql`** (or relevant `.sql` files) for exact table structures and constraints.
- **Consult `specs/07-database/data-dictionary-v1.7.0.md`** for field meanings and business rules.
- **Check `specs/07-database/lcbp3-v1.7.0-seed-basic.sql`** to understand initial data states.
- **Check `specs/07-database/lcbp3-v1.7.0-seed-permissions.sql`** to understand initial permissions states.
- *Constraint:* NEVER invent table names or columns. Use ONLY what is defined here.
5. **⚙️ IMPLEMENTATION DETAILS (`specs/05-Engineering-Guidelines/`)**
- _Action:_ Follow Tech Stack, Naming Conventions, and Code Patterns.
6. **⚙️ IMPLEMENTATION DETAILS (`specs/03-implementation/`)**
- *Action:* Follow Tech Stack, Naming Conventions, and Code Patterns.
7. **🚀 OPERATIONS (`specs/04-operations/`)**
- *Action:* Ensure deployability and configuration compliance.
8. **🏗️ INFRASTRUCTURE (`specs/08-infrastructure/`)**
- *Action:* Review Docker Compose configurations, network diagrams, monitoring setup, and security zones.
- *Constraint:* Ensure deployment paths, port mappings, and volume mounts are consistent with this documentation.
6. **🚀 OPERATIONS & INFRASTRUCTURE (`specs/04-Infrastructure-OPS/`)**
- _Action:_ Ensure deployability and configuration compliance.
- _Constraint:_ Ensure deployment paths, port mappings, and volume mounts are consistent with this documentation.
## Execution Rules
### 1. Citation Requirement
When proposing a change or writing code, you must explicitly reference the source of truth:
> "Implementing feature X per `specs/01-requirements/README.md` and `specs/01-requirements/**.md` using pattern defined in `specs/03-implementation/**.md`."
> "Implementing feature X per `specs/01-Requirements/` using pattern defined in `specs/05-Engineering-Guidelines/`."
### 2. Conflict Resolution
- **Spec vs. Training Data:** The `specs/` folder ALWAYS supersedes your general training data.
- **Spec vs. User Prompt:** If a user prompt contradicts `specs/05-decisions/`, warn the user before proceeding.
- **Spec vs. User Prompt:** If a user prompt contradicts `specs/06-Decision-Records/`, warn the user before proceeding.
### 3. File Generation
- Do not create new files outside of the structure defined.
- Keep the code style consistent with `specs/03-implementation/`.
### 4. Data Migration
- Do not migrate. The schema can be modified directly.
- Do not create new files outside of the established project structure:
- Backend: `backend/src/modules/<name>/`, `backend/src/common/`
- Frontend: `frontend/app/`, `frontend/components/`, `frontend/hooks/`, `frontend/lib/`
- Specs: `specs/` subdirectories only
- Keep the code style consistent with `specs/05-Engineering-Guidelines/`.
- New modules MUST follow the workflow in `.agents/workflows/create-backend-module.md` or `.agents/workflows/create-frontend-page.md`.
### 4. Schema Changes
- **DO NOT** create or run TypeORM migration files.
- Modify the schema directly in `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`.
- Update `specs/03-Data-and-Storage/03-01-data-dictionary.md` if adding/changing columns.
- Notify the user so they can apply the SQL change to the live database manually.
---

View File

@@ -1,15 +1,38 @@
---
trigger: always_on
description: Control which shell commands the agent may run automatically.
allowAuto: ["pnpm test:watch", "pnpm test:debug", "pnpm test:e2e", "git status"]
denyAuto: ["rm -rf", "Remove-Item", "git push --force", "curl | bash"]
allowAuto:
- 'pnpm test:watch'
- 'pnpm test:debug'
- 'pnpm test:e2e'
- 'git status'
- 'git log --oneline'
- 'git diff'
- 'git branch'
- 'tsc --noEmit'
denyAuto:
- 'rm -rf'
- 'Remove-Item'
- 'git push --force'
- 'git reset --hard'
- 'git clean -fd'
- 'curl | bash'
- 'docker compose down'
- 'DROP TABLE'
- 'TRUNCATE'
- 'DELETE FROM'
alwaysReview: true
scopes: ["backend/src/**", "backend/test/**", "frontend/app/**"]
scopes:
- 'backend/src/**'
- 'backend/test/**'
- 'frontend/app/**'
---
# Execution Rules
- Only auto-execute commands that are explicitly listed in `allowAuto`.
- Commands in denyAuto must always be blocked, even if manually requested.
- All shell operations that create, modify, or delete files in `backend/src/` or `backend/test/` or `frontend/app/` require human review.
- Alert if environment variables related to DB connection or secrets would be displayed or logged.
- Commands in `denyAuto` must always be blocked, even if manually requested.
- All shell operations that create, modify, or delete files in `backend/src/`, `backend/test/`, or `frontend/app/` require human review.
- Alert before running any SQL that modifies data (INSERT/UPDATE/DELETE/DROP/TRUNCATE).
- Alert if environment variables related to DB connection or secrets (DATABASE_URL, JWT_SECRET, passwords) would be displayed or logged.
- Never auto-execute commands that expose sensitive credentials via MCP tools or shell output.

206
.agents/README.md Normal file
View File

@@ -0,0 +1,206 @@
# 🚀 Spec-Kit: Antigravity Skills & Workflows
> **The Event Horizon of Software Quality.**
> *Adapted for Google Antigravity IDE from [github/spec-kit](https://github.com/github/spec-kit).*
> *Version: 1.1.0*
---
## 🌟 Overview
Welcome to the **Antigravity Edition** of Spec-Kit. This system is architected to empower your AI pair programmer (Antigravity) to drive the entire Software Development Life Cycle (SDLC) using two powerful mechanisms: **Workflows** and **Skills**.
### 🔄 Dual-Mode Intelligence
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.
> **To understand the power of Skills in Antigravity, read the docs here:**
> [https://antigravity.google/docs/skills](https://antigravity.google/docs/skills)
---
## 🛠️ Installation
To enable these agent capabilities in your project:
1. **Add the folder**: Drop the `.agent/` folder into the root of your project workspace.
2. **That's it!** Antigravity automatically detects the `.agent/skills` and `.agent/workflows` directories. It will instantly gain the ability to perform Spec-Driven Development.
> **💡 Compatibility Note:** This toolkit is fully compatible with **Claude Code**. To use it with Claude, simply rename the `.agent` folder to `.claude`. The skills and workflows will function identically.
---
## 🏗️ The Architecture
The toolkit is organized into modular components that provide both the logic (Scripts) and the structure (Templates) for the agent.
```text
.agent/
├── skills/ # @ Mentions (Agent Intelligence)
│ ├── 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.specify # Feature Definer
│ ├── speckit.status # Progress Dashboard
│ ├── speckit.tasks # Task Breaker
│ ├── speckit.taskstoissues# Issue Tracker Syncer
│ ├── speckit.tester # Test Runner & Coverage
│ └── speckit.validate # Implementation Validator
├── workflows/ # / Slash Commands (Orchestration)
│ ├── 00-speckit.all.md # Full Pipeline
│ ├── 01-speckit.constitution.md # Governance
│ ├── 02-speckit.specify.md # Feature Spec
│ ├── ... (Numbered 00-11)
│ ├── speckit.prepare.md # Prep Pipeline
│ └── util-speckit.*.md # Utilities
└── scripts/ # Shared Bash Core (Kinetic logic)
```
---
## 🗺️ Mapping: Commands to Capabilities
| Phase | Workflow Trigger | Antigravity Skill | Role |
| :--- | :--- | :--- | :--- |
| **Pipeline** | `/00-speckit.all` | N/A | Runs the full SDLC pipeline. |
| **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 sequence. |
| **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/Jira/etc. |
---
## 🛡️ The Quality Assurance Pipeline
The following skills are designed to work together as a comprehensive defense against regression and poor quality. Run them in this order:
| 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. |
> **🤖 Power User Tip:** You can amplify this pipeline by creating a custom **Claude Code (MCP) Server** or subagent that delegates heavy reasoning to **Gemini Pro 3** via the `gemini` CLI.
>
> * **Use Case:** Bind the `@speckit.validate` and `@speckit.reviewer` steps to Gemini Pro 3.
> * **Benefit:** Gemini's 1M+ token context and reasoning capabilities 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 `gemini chat`, then expose this as a tool to Claude.
---
---
## 🏗️ The Design & Management Pipeline
These workflows function as the "Control Plane" of the project, managing everything from idea inception to status tracking.
| Step | Workflow | Core Question | Focus |
| :--- | :--- | :--- | :--- |
| **1. Preparation** | `/speckit.prepare` | *"Are we ready?"* | **The Macro-Workflow**. Runs Skills 0206 (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 real GitHub/Jira issues for the team. |
| **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`**.
**Stage 2: Hardening**
* 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.
---
## 🚀 Getting Started in Antigravity
Once the `.agent` folder is present, you can talk to your agent as a partner. You can trigger a full process using a slash command or reference a specific capability using a skill mention.
**Example Conversation:**
> **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 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?"
>
> **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."
---
## 🏆 Best Practices for Antigravity
To get the most out of this system, follow these **Spec-Driven Development (SDD)** rules:
### 1. The Constitution is King 👑
**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").
* **Tip:** If Antigravity makes a style mistake, don't just fix the code—update the Constitution so it never happens again.
### 2. The Layered Defense 🛡️
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.
### 3. The 15-Minute Rule ⏱️
When generating `tasks.md` (Skill 05), ensure tasks are **atomic**.
* **Bad Task**: "Implement User Auth" (Too big, AI will get lost).
* **Good Task**: "Create `User` Mongoose schema with email validation" (Perfect).
* **Rule of Thumb**: If a task takes Antigravity more than 3 tool calls to finish, it's too big. Break it down.
### 4. "Refine, Don't Rewind" ⏩
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.
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.
* **Shared Script Core**: All logic resides in `.agent/scripts/bash` for consistent file and git operations.
* **Agent-Native**: Designed to be invoked via Antigravity tool calls and reasoning rather than just terminal strings.
---
*Built with logic from [Spec-Kit](https://github.com/github/spec-kit). Powered by Antigravity.*

View File

@@ -0,0 +1,166 @@
#!/usr/bin/env bash
# Consolidated prerequisite checking script
#
# This script provides unified prerequisite checking for Spec-Driven Development workflow.
# It replaces the functionality previously spread across multiple scripts.
#
# Usage: ./check-prerequisites.sh [OPTIONS]
#
# OPTIONS:
# --json Output in JSON format
# --require-tasks Require tasks.md to exist (for implementation phase)
# --include-tasks Include tasks.md in AVAILABLE_DOCS list
# --paths-only Only output path variables (no validation)
# --help, -h Show help message
#
# OUTPUTS:
# JSON mode: {"FEATURE_DIR":"...", "AVAILABLE_DOCS":["..."]}
# Text mode: FEATURE_DIR:... \n AVAILABLE_DOCS: \n ✓/✗ file.md
# Paths only: REPO_ROOT: ... \n BRANCH: ... \n FEATURE_DIR: ... etc.
set -e
# Parse command line arguments
JSON_MODE=false
REQUIRE_TASKS=false
INCLUDE_TASKS=false
PATHS_ONLY=false
for arg in "$@"; do
case "$arg" in
--json)
JSON_MODE=true
;;
--require-tasks)
REQUIRE_TASKS=true
;;
--include-tasks)
INCLUDE_TASKS=true
;;
--paths-only)
PATHS_ONLY=true
;;
--help|-h)
cat << 'EOF'
Usage: check-prerequisites.sh [OPTIONS]
Consolidated prerequisite checking for Spec-Driven Development workflow.
OPTIONS:
--json Output in JSON format
--require-tasks Require tasks.md to exist (for implementation phase)
--include-tasks Include tasks.md in AVAILABLE_DOCS list
--paths-only Only output path variables (no prerequisite validation)
--help, -h Show this help message
EXAMPLES:
# Check task prerequisites (plan.md required)
./check-prerequisites.sh --json
# Check implementation prerequisites (plan.md + tasks.md required)
./check-prerequisites.sh --json --require-tasks --include-tasks
# Get feature paths only (no validation)
./check-prerequisites.sh --paths-only
EOF
exit 0
;;
*)
echo "ERROR: Unknown option '$arg'. Use --help for usage information." >&2
exit 1
;;
esac
done
# Source common functions
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
# Get feature paths and validate branch
eval $(get_feature_paths)
check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1
# If paths-only mode, output paths and exit (support JSON + paths-only combined)
if $PATHS_ONLY; then
if $JSON_MODE; then
# Minimal JSON paths payload (no validation performed)
printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \
"$REPO_ROOT" "$CURRENT_BRANCH" "$FEATURE_DIR" "$FEATURE_SPEC" "$IMPL_PLAN" "$TASKS"
else
echo "REPO_ROOT: $REPO_ROOT"
echo "BRANCH: $CURRENT_BRANCH"
echo "FEATURE_DIR: $FEATURE_DIR"
echo "FEATURE_SPEC: $FEATURE_SPEC"
echo "IMPL_PLAN: $IMPL_PLAN"
echo "TASKS: $TASKS"
fi
exit 0
fi
# Validate required directories and files
if [[ ! -d "$FEATURE_DIR" ]]; then
echo "ERROR: Feature directory not found: $FEATURE_DIR" >&2
echo "Run /speckit.specify first to create the feature structure." >&2
exit 1
fi
if [[ ! -f "$IMPL_PLAN" ]]; then
echo "ERROR: plan.md not found in $FEATURE_DIR" >&2
echo "Run /speckit.plan first to create the implementation plan." >&2
exit 1
fi
# Check for tasks.md if required
if $REQUIRE_TASKS && [[ ! -f "$TASKS" ]]; then
echo "ERROR: tasks.md not found in $FEATURE_DIR" >&2
echo "Run /speckit.tasks first to create the task list." >&2
exit 1
fi
# Build list of available documents
docs=()
# Always check these optional docs
[[ -f "$RESEARCH" ]] && docs+=("research.md")
[[ -f "$DATA_MODEL" ]] && docs+=("data-model.md")
# Check contracts directory (only if it exists and has files)
if [[ -d "$CONTRACTS_DIR" ]] && [[ -n "$(ls -A "$CONTRACTS_DIR" 2>/dev/null)" ]]; then
docs+=("contracts/")
fi
[[ -f "$QUICKSTART" ]] && docs+=("quickstart.md")
# Include tasks.md if requested and it exists
if $INCLUDE_TASKS && [[ -f "$TASKS" ]]; then
docs+=("tasks.md")
fi
# Output results
if $JSON_MODE; then
# Build JSON array of documents
if [[ ${#docs[@]} -eq 0 ]]; then
json_docs="[]"
else
json_docs=$(printf '"%s",' "${docs[@]}")
json_docs="[${json_docs%,}]"
fi
printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s}\n' "$FEATURE_DIR" "$json_docs"
else
# Text output
echo "FEATURE_DIR:$FEATURE_DIR"
echo "AVAILABLE_DOCS:"
# Show status of each potential document
check_file "$RESEARCH" "research.md"
check_file "$DATA_MODEL" "data-model.md"
check_dir "$CONTRACTS_DIR" "contracts/"
check_file "$QUICKSTART" "quickstart.md"
if $INCLUDE_TASKS; then
check_file "$TASKS" "tasks.md"
fi
fi

View File

@@ -0,0 +1,156 @@
#!/usr/bin/env bash
# Common functions and variables for all scripts
# Get repository root, with fallback for non-git repositories
get_repo_root() {
if git rev-parse --show-toplevel >/dev/null 2>&1; then
git rev-parse --show-toplevel
else
# Fall back to script location for non-git repos
local script_dir="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
(cd "$script_dir/../../.." && pwd)
fi
}
# Get current branch, with fallback for non-git repositories
get_current_branch() {
# First check if SPECIFY_FEATURE environment variable is set
if [[ -n "${SPECIFY_FEATURE:-}" ]]; then
echo "$SPECIFY_FEATURE"
return
fi
# Then check git if available
if git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then
git rev-parse --abbrev-ref HEAD
return
fi
# For non-git repos, try to find the latest feature directory
local repo_root=$(get_repo_root)
local specs_dir="$repo_root/specs"
if [[ -d "$specs_dir" ]]; then
local latest_feature=""
local highest=0
for dir in "$specs_dir"/*; do
if [[ -d "$dir" ]]; then
local dirname=$(basename "$dir")
if [[ "$dirname" =~ ^([0-9]{3})- ]]; then
local number=${BASH_REMATCH[1]}
number=$((10#$number))
if [[ "$number" -gt "$highest" ]]; then
highest=$number
latest_feature=$dirname
fi
fi
fi
done
if [[ -n "$latest_feature" ]]; then
echo "$latest_feature"
return
fi
fi
echo "main" # Final fallback
}
# Check if we have git available
has_git() {
git rev-parse --show-toplevel >/dev/null 2>&1
}
check_feature_branch() {
local branch="$1"
local has_git_repo="$2"
# For non-git repos, we can't enforce branch naming but still provide output
if [[ "$has_git_repo" != "true" ]]; then
echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2
return 0
fi
if [[ ! "$branch" =~ ^[0-9]{3}- ]]; then
echo "ERROR: Not on a feature branch. Current branch: $branch" >&2
echo "Feature branches should be named like: 001-feature-name" >&2
return 1
fi
return 0
}
get_feature_dir() { echo "$1/specs/$2"; }
# Find feature directory by numeric prefix instead of exact branch match
# This allows multiple branches to work on the same spec (e.g., 004-fix-bug, 004-add-feature)
find_feature_dir_by_prefix() {
local repo_root="$1"
local branch_name="$2"
local specs_dir="$repo_root/specs"
# Extract numeric prefix from branch (e.g., "004" from "004-whatever")
if [[ ! "$branch_name" =~ ^([0-9]{3})- ]]; then
# If branch doesn't have numeric prefix, fall back to exact match
echo "$specs_dir/$branch_name"
return
fi
local prefix="${BASH_REMATCH[1]}"
# Search for directories in specs/ that start with this prefix
local matches=()
if [[ -d "$specs_dir" ]]; then
for dir in "$specs_dir"/"$prefix"-*; do
if [[ -d "$dir" ]]; then
matches+=("$(basename "$dir")")
fi
done
fi
# Handle results
if [[ ${#matches[@]} -eq 0 ]]; then
# No match found - return the branch name path (will fail later with clear error)
echo "$specs_dir/$branch_name"
elif [[ ${#matches[@]} -eq 1 ]]; then
# Exactly one match - perfect!
echo "$specs_dir/${matches[0]}"
else
# Multiple matches - this shouldn't happen with proper naming convention
echo "ERROR: Multiple spec directories found with prefix '$prefix': ${matches[*]}" >&2
echo "Please ensure only one spec directory exists per numeric prefix." >&2
echo "$specs_dir/$branch_name" # Return something to avoid breaking the script
fi
}
get_feature_paths() {
local repo_root=$(get_repo_root)
local current_branch=$(get_current_branch)
local has_git_repo="false"
if has_git; then
has_git_repo="true"
fi
# Use prefix-based lookup to support multiple branches per spec
local feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch")
cat <<EOF
REPO_ROOT='$repo_root'
CURRENT_BRANCH='$current_branch'
HAS_GIT='$has_git_repo'
FEATURE_DIR='$feature_dir'
FEATURE_SPEC='$feature_dir/spec.md'
IMPL_PLAN='$feature_dir/plan.md'
TASKS='$feature_dir/tasks.md'
RESEARCH='$feature_dir/research.md'
DATA_MODEL='$feature_dir/data-model.md'
QUICKSTART='$feature_dir/quickstart.md'
CONTRACTS_DIR='$feature_dir/contracts'
EOF
}
check_file() { [[ -f "$1" ]] && echo "$2" || echo "$2"; }
check_dir() { [[ -d "$1" && -n $(ls -A "$1" 2>/dev/null) ]] && echo "$2" || echo "$2"; }

View File

@@ -0,0 +1,297 @@
#!/usr/bin/env bash
set -e
JSON_MODE=false
SHORT_NAME=""
BRANCH_NUMBER=""
ARGS=()
i=1
while [ $i -le $# ]; do
arg="${!i}"
case "$arg" in
--json)
JSON_MODE=true
;;
--short-name)
if [ $((i + 1)) -gt $# ]; then
echo 'Error: --short-name requires a value' >&2
exit 1
fi
i=$((i + 1))
next_arg="${!i}"
# Check if the next argument is another option (starts with --)
if [[ "$next_arg" == --* ]]; then
echo 'Error: --short-name requires a value' >&2
exit 1
fi
SHORT_NAME="$next_arg"
;;
--number)
if [ $((i + 1)) -gt $# ]; then
echo 'Error: --number requires a value' >&2
exit 1
fi
i=$((i + 1))
next_arg="${!i}"
if [[ "$next_arg" == --* ]]; then
echo 'Error: --number requires a value' >&2
exit 1
fi
BRANCH_NUMBER="$next_arg"
;;
--help|-h)
echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>"
echo ""
echo "Options:"
echo " --json Output in JSON format"
echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
echo " --number N Specify branch number manually (overrides auto-detection)"
echo " --help, -h Show this help message"
echo ""
echo "Examples:"
echo " $0 'Add user authentication system' --short-name 'user-auth'"
echo " $0 'Implement OAuth2 integration for API' --number 5"
exit 0
;;
*)
ARGS+=("$arg")
;;
esac
i=$((i + 1))
done
FEATURE_DESCRIPTION="${ARGS[*]}"
if [ -z "$FEATURE_DESCRIPTION" ]; then
echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>" >&2
exit 1
fi
# Function to find the repository root by searching for existing project markers
find_repo_root() {
local dir="$1"
while [ "$dir" != "/" ]; do
if [ -d "$dir/.git" ] || [ -d "$dir/.specify" ]; then
echo "$dir"
return 0
fi
dir="$(dirname "$dir")"
done
return 1
}
# Function to get highest number from specs directory
get_highest_from_specs() {
local specs_dir="$1"
local highest=0
if [ -d "$specs_dir" ]; then
for dir in "$specs_dir"/*; do
[ -d "$dir" ] || continue
dirname=$(basename "$dir")
number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0")
number=$((10#$number))
if [ "$number" -gt "$highest" ]; then
highest=$number
fi
done
fi
echo "$highest"
}
# Function to get highest number from git branches
get_highest_from_branches() {
local highest=0
# Get all branches (local and remote)
branches=$(git branch -a 2>/dev/null || echo "")
if [ -n "$branches" ]; then
while IFS= read -r branch; do
# Clean branch name: remove leading markers and remote prefixes
clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||')
# Extract feature number if branch matches pattern ###-*
if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then
number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0")
number=$((10#$number))
if [ "$number" -gt "$highest" ]; then
highest=$number
fi
fi
done <<< "$branches"
fi
echo "$highest"
}
# Function to check existing branches (local and remote) and return next available number
check_existing_branches() {
local specs_dir="$1"
# Fetch all remotes to get latest branch info (suppress errors if no remotes)
git fetch --all --prune 2>/dev/null || true
# Get highest number from ALL branches (not just matching short name)
local highest_branch=$(get_highest_from_branches)
# Get highest number from ALL specs (not just matching short name)
local highest_spec=$(get_highest_from_specs "$specs_dir")
# Take the maximum of both
local max_num=$highest_branch
if [ "$highest_spec" -gt "$max_num" ]; then
max_num=$highest_spec
fi
# Return next number
echo $((max_num + 1))
}
# Function to clean and format a branch name
clean_branch_name() {
local name="$1"
echo "$name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//'
}
# Resolve repository root. Prefer git information when available, but fall back
# to searching for repository markers so the workflow still functions in repositories that
# were initialised with --no-git.
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if git rev-parse --show-toplevel >/dev/null 2>&1; then
REPO_ROOT=$(git rev-parse --show-toplevel)
HAS_GIT=true
else
REPO_ROOT="$(find_repo_root "$SCRIPT_DIR")"
if [ -z "$REPO_ROOT" ]; then
echo "Error: Could not determine repository root. Please run this script from within the repository." >&2
exit 1
fi
HAS_GIT=false
fi
cd "$REPO_ROOT"
SPECS_DIR="$REPO_ROOT/specs"
mkdir -p "$SPECS_DIR"
# Function to generate branch name with stop word filtering and length filtering
generate_branch_name() {
local description="$1"
# Common stop words to filter out
local stop_words="^(i|a|an|the|to|for|of|in|on|at|by|with|from|is|are|was|were|be|been|being|have|has|had|do|does|did|will|would|should|could|can|may|might|must|shall|this|that|these|those|my|your|our|their|want|need|add|get|set)$"
# Convert to lowercase and split into words
local clean_name=$(echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
# Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
local meaningful_words=()
for word in $clean_name; do
# Skip empty words
[ -z "$word" ] && continue
# Keep words that are NOT stop words AND (length >= 3 OR are potential acronyms)
if ! echo "$word" | grep -qiE "$stop_words"; then
if [ ${#word} -ge 3 ]; then
meaningful_words+=("$word")
elif echo "$description" | grep -q "\b${word^^}\b"; then
# Keep short words if they appear as uppercase in original (likely acronyms)
meaningful_words+=("$word")
fi
fi
done
# If we have meaningful words, use first 3-4 of them
if [ ${#meaningful_words[@]} -gt 0 ]; then
local max_words=3
if [ ${#meaningful_words[@]} -eq 4 ]; then max_words=4; fi
local result=""
local count=0
for word in "${meaningful_words[@]}"; do
if [ $count -ge $max_words ]; then break; fi
if [ -n "$result" ]; then result="$result-"; fi
result="$result$word"
count=$((count + 1))
done
echo "$result"
else
# Fallback to original logic if no meaningful words found
local cleaned=$(clean_branch_name "$description")
echo "$cleaned" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//'
fi
}
# Generate branch name
if [ -n "$SHORT_NAME" ]; then
# Use provided short name, just clean it up
BRANCH_SUFFIX=$(clean_branch_name "$SHORT_NAME")
else
# Generate from description with smart filtering
BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
fi
# Determine branch number
if [ -z "$BRANCH_NUMBER" ]; then
if [ "$HAS_GIT" = true ]; then
# Check existing branches on remotes
BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR")
else
# Fall back to local directory check
HIGHEST=$(get_highest_from_specs "$SPECS_DIR")
BRANCH_NUMBER=$((HIGHEST + 1))
fi
fi
# Force base-10 interpretation to prevent octal conversion (e.g., 010 → 8 in octal, but should be 10 in decimal)
FEATURE_NUM=$(printf "%03d" "$((10#$BRANCH_NUMBER))")
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
# GitHub enforces a 244-byte limit on branch names
# Validate and truncate if necessary
MAX_BRANCH_LENGTH=244
if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
# Calculate how much we need to trim from suffix
# Account for: feature number (3) + hyphen (1) = 4 chars
MAX_SUFFIX_LENGTH=$((MAX_BRANCH_LENGTH - 4))
# Truncate suffix at word boundary if possible
TRUNCATED_SUFFIX=$(echo "$BRANCH_SUFFIX" | cut -c1-$MAX_SUFFIX_LENGTH)
# Remove trailing hyphen if truncation created one
TRUNCATED_SUFFIX=$(echo "$TRUNCATED_SUFFIX" | sed 's/-$//')
ORIGINAL_BRANCH_NAME="$BRANCH_NAME"
BRANCH_NAME="${FEATURE_NUM}-${TRUNCATED_SUFFIX}"
>&2 echo "[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
>&2 echo "[specify] Original: $ORIGINAL_BRANCH_NAME (${#ORIGINAL_BRANCH_NAME} bytes)"
>&2 echo "[specify] Truncated to: $BRANCH_NAME (${#BRANCH_NAME} bytes)"
fi
if [ "$HAS_GIT" = true ]; then
git checkout -b "$BRANCH_NAME"
else
>&2 echo "[specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME"
fi
FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME"
mkdir -p "$FEATURE_DIR"
TEMPLATE="$REPO_ROOT/.specify/templates/spec-template.md"
SPEC_FILE="$FEATURE_DIR/spec.md"
if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE"; fi
# Set the SPECIFY_FEATURE environment variable for the current session
export SPECIFY_FEATURE="$BRANCH_NAME"
if $JSON_MODE; then
printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' "$BRANCH_NAME" "$SPEC_FILE" "$FEATURE_NUM"
else
echo "BRANCH_NAME: $BRANCH_NAME"
echo "SPEC_FILE: $SPEC_FILE"
echo "FEATURE_NUM: $FEATURE_NUM"
echo "SPECIFY_FEATURE environment variable set to: $BRANCH_NAME"
fi

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -e
# Parse command line arguments
JSON_MODE=false
ARGS=()
for arg in "$@"; do
case "$arg" in
--json)
JSON_MODE=true
;;
--help|-h)
echo "Usage: $0 [--json]"
echo " --json Output results in JSON format"
echo " --help Show this help message"
exit 0
;;
*)
ARGS+=("$arg")
;;
esac
done
# Get script directory and load common functions
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
# Get all paths and variables from common functions
eval $(get_feature_paths)
# Check if we're on a proper feature branch (only for git repos)
check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1
# Ensure the feature directory exists
mkdir -p "$FEATURE_DIR"
# Copy plan template if it exists
TEMPLATE="$REPO_ROOT/.specify/templates/plan-template.md"
if [[ -f "$TEMPLATE" ]]; then
cp "$TEMPLATE" "$IMPL_PLAN"
echo "Copied plan template to $IMPL_PLAN"
else
echo "Warning: Plan template not found at $TEMPLATE"
# Create a basic plan file if template doesn't exist
touch "$IMPL_PLAN"
fi
# Output results
if $JSON_MODE; then
printf '{"FEATURE_SPEC":"%s","IMPL_PLAN":"%s","SPECS_DIR":"%s","BRANCH":"%s","HAS_GIT":"%s"}\n' \
"$FEATURE_SPEC" "$IMPL_PLAN" "$FEATURE_DIR" "$CURRENT_BRANCH" "$HAS_GIT"
else
echo "FEATURE_SPEC: $FEATURE_SPEC"
echo "IMPL_PLAN: $IMPL_PLAN"
echo "SPECS_DIR: $FEATURE_DIR"
echo "BRANCH: $CURRENT_BRANCH"
echo "HAS_GIT: $HAS_GIT"
fi

View File

@@ -0,0 +1,799 @@
#!/usr/bin/env bash
# Update agent context files with information from plan.md
#
# This script maintains AI agent context files by parsing feature specifications
# and updating agent-specific configuration files with project information.
#
# MAIN FUNCTIONS:
# 1. Environment Validation
# - Verifies git repository structure and branch information
# - Checks for required plan.md files and templates
# - Validates file permissions and accessibility
#
# 2. Plan Data Extraction
# - Parses plan.md files to extract project metadata
# - Identifies language/version, frameworks, databases, and project types
# - Handles missing or incomplete specification data gracefully
#
# 3. Agent File Management
# - Creates new agent context files from templates when needed
# - Updates existing agent files with new project information
# - Preserves manual additions and custom configurations
# - Supports multiple AI agent formats and directory structures
#
# 4. Content Generation
# - Generates language-specific build/test commands
# - Creates appropriate project directory structures
# - Updates technology stacks and recent changes sections
# - Maintains consistent formatting and timestamps
#
# 5. Multi-Agent Support
# - Handles agent-specific file paths and naming conventions
# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Qoder CLI, Amp, SHAI, or Amazon Q Developer CLI
# - Can update single agents or all existing agent files
# - Creates default Claude file if no agent files exist
#
# Usage: ./update-agent-context.sh [agent_type]
# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|shai|q|bob|qoder
# Leave empty to update all existing agent files
set -e
# Enable strict error handling
set -u
set -o pipefail
#==============================================================================
# Configuration and Global Variables
#==============================================================================
# Get script directory and load common functions
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
# Get all paths and variables from common functions
eval $(get_feature_paths)
NEW_PLAN="$IMPL_PLAN" # Alias for compatibility with existing code
AGENT_TYPE="${1:-}"
# Agent-specific file paths
CLAUDE_FILE="$REPO_ROOT/CLAUDE.md"
GEMINI_FILE="$REPO_ROOT/GEMINI.md"
COPILOT_FILE="$REPO_ROOT/.github/agents/copilot-instructions.md"
CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc"
QWEN_FILE="$REPO_ROOT/QWEN.md"
AGENTS_FILE="$REPO_ROOT/AGENTS.md"
WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
KILOCODE_FILE="$REPO_ROOT/.kilocode/rules/specify-rules.md"
AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md"
ROO_FILE="$REPO_ROOT/.roo/rules/specify-rules.md"
CODEBUDDY_FILE="$REPO_ROOT/CODEBUDDY.md"
QODER_FILE="$REPO_ROOT/QODER.md"
AMP_FILE="$REPO_ROOT/AGENTS.md"
SHAI_FILE="$REPO_ROOT/SHAI.md"
Q_FILE="$REPO_ROOT/AGENTS.md"
BOB_FILE="$REPO_ROOT/AGENTS.md"
# Template file
TEMPLATE_FILE="$REPO_ROOT/.specify/templates/agent-file-template.md"
# Global variables for parsed plan data
NEW_LANG=""
NEW_FRAMEWORK=""
NEW_DB=""
NEW_PROJECT_TYPE=""
#==============================================================================
# Utility Functions
#==============================================================================
log_info() {
echo "INFO: $1"
}
log_success() {
echo "$1"
}
log_error() {
echo "ERROR: $1" >&2
}
log_warning() {
echo "WARNING: $1" >&2
}
# Cleanup function for temporary files
cleanup() {
local exit_code=$?
rm -f /tmp/agent_update_*_$$
rm -f /tmp/manual_additions_$$
exit $exit_code
}
# Set up cleanup trap
trap cleanup EXIT INT TERM
#==============================================================================
# Validation Functions
#==============================================================================
validate_environment() {
# Check if we have a current branch/feature (git or non-git)
if [[ -z "$CURRENT_BRANCH" ]]; then
log_error "Unable to determine current feature"
if [[ "$HAS_GIT" == "true" ]]; then
log_info "Make sure you're on a feature branch"
else
log_info "Set SPECIFY_FEATURE environment variable or create a feature first"
fi
exit 1
fi
# Check if plan.md exists
if [[ ! -f "$NEW_PLAN" ]]; then
log_error "No plan.md found at $NEW_PLAN"
log_info "Make sure you're working on a feature with a corresponding spec directory"
if [[ "$HAS_GIT" != "true" ]]; then
log_info "Use: export SPECIFY_FEATURE=your-feature-name or create a new feature first"
fi
exit 1
fi
# Check if template exists (needed for new files)
if [[ ! -f "$TEMPLATE_FILE" ]]; then
log_warning "Template file not found at $TEMPLATE_FILE"
log_warning "Creating new agent files will fail"
fi
}
#==============================================================================
# Plan Parsing Functions
#==============================================================================
extract_plan_field() {
local field_pattern="$1"
local plan_file="$2"
grep "^\*\*${field_pattern}\*\*: " "$plan_file" 2>/dev/null | \
head -1 | \
sed "s|^\*\*${field_pattern}\*\*: ||" | \
sed 's/^[ \t]*//;s/[ \t]*$//' | \
grep -v "NEEDS CLARIFICATION" | \
grep -v "^N/A$" || echo ""
}
parse_plan_data() {
local plan_file="$1"
if [[ ! -f "$plan_file" ]]; then
log_error "Plan file not found: $plan_file"
return 1
fi
if [[ ! -r "$plan_file" ]]; then
log_error "Plan file is not readable: $plan_file"
return 1
fi
log_info "Parsing plan data from $plan_file"
NEW_LANG=$(extract_plan_field "Language/Version" "$plan_file")
NEW_FRAMEWORK=$(extract_plan_field "Primary Dependencies" "$plan_file")
NEW_DB=$(extract_plan_field "Storage" "$plan_file")
NEW_PROJECT_TYPE=$(extract_plan_field "Project Type" "$plan_file")
# Log what we found
if [[ -n "$NEW_LANG" ]]; then
log_info "Found language: $NEW_LANG"
else
log_warning "No language information found in plan"
fi
if [[ -n "$NEW_FRAMEWORK" ]]; then
log_info "Found framework: $NEW_FRAMEWORK"
fi
if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]]; then
log_info "Found database: $NEW_DB"
fi
if [[ -n "$NEW_PROJECT_TYPE" ]]; then
log_info "Found project type: $NEW_PROJECT_TYPE"
fi
}
format_technology_stack() {
local lang="$1"
local framework="$2"
local parts=()
# Add non-empty parts
[[ -n "$lang" && "$lang" != "NEEDS CLARIFICATION" ]] && parts+=("$lang")
[[ -n "$framework" && "$framework" != "NEEDS CLARIFICATION" && "$framework" != "N/A" ]] && parts+=("$framework")
# Join with proper formatting
if [[ ${#parts[@]} -eq 0 ]]; then
echo ""
elif [[ ${#parts[@]} -eq 1 ]]; then
echo "${parts[0]}"
else
# Join multiple parts with " + "
local result="${parts[0]}"
for ((i=1; i<${#parts[@]}; i++)); do
result="$result + ${parts[i]}"
done
echo "$result"
fi
}
#==============================================================================
# Template and Content Generation Functions
#==============================================================================
get_project_structure() {
local project_type="$1"
if [[ "$project_type" == *"web"* ]]; then
echo "backend/\\nfrontend/\\ntests/"
else
echo "src/\\ntests/"
fi
}
get_commands_for_language() {
local lang="$1"
case "$lang" in
*"Python"*)
echo "cd src && pytest && ruff check ."
;;
*"Rust"*)
echo "cargo test && cargo clippy"
;;
*"JavaScript"*|*"TypeScript"*)
echo "npm test \\&\\& npm run lint"
;;
*)
echo "# Add commands for $lang"
;;
esac
}
get_language_conventions() {
local lang="$1"
echo "$lang: Follow standard conventions"
}
create_new_agent_file() {
local target_file="$1"
local temp_file="$2"
local project_name="$3"
local current_date="$4"
if [[ ! -f "$TEMPLATE_FILE" ]]; then
log_error "Template not found at $TEMPLATE_FILE"
return 1
fi
if [[ ! -r "$TEMPLATE_FILE" ]]; then
log_error "Template file is not readable: $TEMPLATE_FILE"
return 1
fi
log_info "Creating new agent context file from template..."
if ! cp "$TEMPLATE_FILE" "$temp_file"; then
log_error "Failed to copy template file"
return 1
fi
# Replace template placeholders
local project_structure
project_structure=$(get_project_structure "$NEW_PROJECT_TYPE")
local commands
commands=$(get_commands_for_language "$NEW_LANG")
local language_conventions
language_conventions=$(get_language_conventions "$NEW_LANG")
# Perform substitutions with error checking using safer approach
# Escape special characters for sed by using a different delimiter or escaping
local escaped_lang=$(printf '%s\n' "$NEW_LANG" | sed 's/[\[\.*^$()+{}|]/\\&/g')
local escaped_framework=$(printf '%s\n' "$NEW_FRAMEWORK" | sed 's/[\[\.*^$()+{}|]/\\&/g')
local escaped_branch=$(printf '%s\n' "$CURRENT_BRANCH" | sed 's/[\[\.*^$()+{}|]/\\&/g')
# Build technology stack and recent change strings conditionally
local tech_stack
if [[ -n "$escaped_lang" && -n "$escaped_framework" ]]; then
tech_stack="- $escaped_lang + $escaped_framework ($escaped_branch)"
elif [[ -n "$escaped_lang" ]]; then
tech_stack="- $escaped_lang ($escaped_branch)"
elif [[ -n "$escaped_framework" ]]; then
tech_stack="- $escaped_framework ($escaped_branch)"
else
tech_stack="- ($escaped_branch)"
fi
local recent_change
if [[ -n "$escaped_lang" && -n "$escaped_framework" ]]; then
recent_change="- $escaped_branch: Added $escaped_lang + $escaped_framework"
elif [[ -n "$escaped_lang" ]]; then
recent_change="- $escaped_branch: Added $escaped_lang"
elif [[ -n "$escaped_framework" ]]; then
recent_change="- $escaped_branch: Added $escaped_framework"
else
recent_change="- $escaped_branch: Added"
fi
local substitutions=(
"s|\[PROJECT NAME\]|$project_name|"
"s|\[DATE\]|$current_date|"
"s|\[EXTRACTED FROM ALL PLAN.MD FILES\]|$tech_stack|"
"s|\[ACTUAL STRUCTURE FROM PLANS\]|$project_structure|g"
"s|\[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES\]|$commands|"
"s|\[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE\]|$language_conventions|"
"s|\[LAST 3 FEATURES AND WHAT THEY ADDED\]|$recent_change|"
)
for substitution in "${substitutions[@]}"; do
if ! sed -i.bak -e "$substitution" "$temp_file"; then
log_error "Failed to perform substitution: $substitution"
rm -f "$temp_file" "$temp_file.bak"
return 1
fi
done
# Convert \n sequences to actual newlines
newline=$(printf '\n')
sed -i.bak2 "s/\\\\n/${newline}/g" "$temp_file"
# Clean up backup files
rm -f "$temp_file.bak" "$temp_file.bak2"
return 0
}
update_existing_agent_file() {
local target_file="$1"
local current_date="$2"
log_info "Updating existing agent context file..."
# Use a single temporary file for atomic update
local temp_file
temp_file=$(mktemp) || {
log_error "Failed to create temporary file"
return 1
}
# Process the file in one pass
local tech_stack=$(format_technology_stack "$NEW_LANG" "$NEW_FRAMEWORK")
local new_tech_entries=()
local new_change_entry=""
# Prepare new technology entries
if [[ -n "$tech_stack" ]] && ! grep -q "$tech_stack" "$target_file"; then
new_tech_entries+=("- $tech_stack ($CURRENT_BRANCH)")
fi
if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]] && [[ "$NEW_DB" != "NEEDS CLARIFICATION" ]] && ! grep -q "$NEW_DB" "$target_file"; then
new_tech_entries+=("- $NEW_DB ($CURRENT_BRANCH)")
fi
# Prepare new change entry
if [[ -n "$tech_stack" ]]; then
new_change_entry="- $CURRENT_BRANCH: Added $tech_stack"
elif [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]] && [[ "$NEW_DB" != "NEEDS CLARIFICATION" ]]; then
new_change_entry="- $CURRENT_BRANCH: Added $NEW_DB"
fi
# Check if sections exist in the file
local has_active_technologies=0
local has_recent_changes=0
if grep -q "^## Active Technologies" "$target_file" 2>/dev/null; then
has_active_technologies=1
fi
if grep -q "^## Recent Changes" "$target_file" 2>/dev/null; then
has_recent_changes=1
fi
# Process file line by line
local in_tech_section=false
local in_changes_section=false
local tech_entries_added=false
local changes_entries_added=false
local existing_changes_count=0
local file_ended=false
while IFS= read -r line || [[ -n "$line" ]]; do
# Handle Active Technologies section
if [[ "$line" == "## Active Technologies" ]]; then
echo "$line" >> "$temp_file"
in_tech_section=true
continue
elif [[ $in_tech_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then
# Add new tech entries before closing the section
if [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
tech_entries_added=true
fi
echo "$line" >> "$temp_file"
in_tech_section=false
continue
elif [[ $in_tech_section == true ]] && [[ -z "$line" ]]; then
# Add new tech entries before empty line in tech section
if [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
tech_entries_added=true
fi
echo "$line" >> "$temp_file"
continue
fi
# Handle Recent Changes section
if [[ "$line" == "## Recent Changes" ]]; then
echo "$line" >> "$temp_file"
# Add new change entry right after the heading
if [[ -n "$new_change_entry" ]]; then
echo "$new_change_entry" >> "$temp_file"
fi
in_changes_section=true
changes_entries_added=true
continue
elif [[ $in_changes_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then
echo "$line" >> "$temp_file"
in_changes_section=false
continue
elif [[ $in_changes_section == true ]] && [[ "$line" == "- "* ]]; then
# Keep only first 2 existing changes
if [[ $existing_changes_count -lt 2 ]]; then
echo "$line" >> "$temp_file"
((existing_changes_count++))
fi
continue
fi
# Update timestamp
if [[ "$line" =~ \*\*Last\ updated\*\*:.*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] ]]; then
echo "$line" | sed "s/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/$current_date/" >> "$temp_file"
else
echo "$line" >> "$temp_file"
fi
done < "$target_file"
# Post-loop check: if we're still in the Active Technologies section and haven't added new entries
if [[ $in_tech_section == true ]] && [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
tech_entries_added=true
fi
# If sections don't exist, add them at the end of the file
if [[ $has_active_technologies -eq 0 ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
echo "" >> "$temp_file"
echo "## Active Technologies" >> "$temp_file"
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
tech_entries_added=true
fi
if [[ $has_recent_changes -eq 0 ]] && [[ -n "$new_change_entry" ]]; then
echo "" >> "$temp_file"
echo "## Recent Changes" >> "$temp_file"
echo "$new_change_entry" >> "$temp_file"
changes_entries_added=true
fi
# Move temp file to target atomically
if ! mv "$temp_file" "$target_file"; then
log_error "Failed to update target file"
rm -f "$temp_file"
return 1
fi
return 0
}
#==============================================================================
# Main Agent File Update Function
#==============================================================================
update_agent_file() {
local target_file="$1"
local agent_name="$2"
if [[ -z "$target_file" ]] || [[ -z "$agent_name" ]]; then
log_error "update_agent_file requires target_file and agent_name parameters"
return 1
fi
log_info "Updating $agent_name context file: $target_file"
local project_name
project_name=$(basename "$REPO_ROOT")
local current_date
current_date=$(date +%Y-%m-%d)
# Create directory if it doesn't exist
local target_dir
target_dir=$(dirname "$target_file")
if [[ ! -d "$target_dir" ]]; then
if ! mkdir -p "$target_dir"; then
log_error "Failed to create directory: $target_dir"
return 1
fi
fi
if [[ ! -f "$target_file" ]]; then
# Create new file from template
local temp_file
temp_file=$(mktemp) || {
log_error "Failed to create temporary file"
return 1
}
if create_new_agent_file "$target_file" "$temp_file" "$project_name" "$current_date"; then
if mv "$temp_file" "$target_file"; then
log_success "Created new $agent_name context file"
else
log_error "Failed to move temporary file to $target_file"
rm -f "$temp_file"
return 1
fi
else
log_error "Failed to create new agent file"
rm -f "$temp_file"
return 1
fi
else
# Update existing file
if [[ ! -r "$target_file" ]]; then
log_error "Cannot read existing file: $target_file"
return 1
fi
if [[ ! -w "$target_file" ]]; then
log_error "Cannot write to existing file: $target_file"
return 1
fi
if update_existing_agent_file "$target_file" "$current_date"; then
log_success "Updated existing $agent_name context file"
else
log_error "Failed to update existing agent file"
return 1
fi
fi
return 0
}
#==============================================================================
# Agent Selection and Processing
#==============================================================================
update_specific_agent() {
local agent_type="$1"
case "$agent_type" in
claude)
update_agent_file "$CLAUDE_FILE" "Claude Code"
;;
gemini)
update_agent_file "$GEMINI_FILE" "Gemini CLI"
;;
copilot)
update_agent_file "$COPILOT_FILE" "GitHub Copilot"
;;
cursor-agent)
update_agent_file "$CURSOR_FILE" "Cursor IDE"
;;
qwen)
update_agent_file "$QWEN_FILE" "Qwen Code"
;;
opencode)
update_agent_file "$AGENTS_FILE" "opencode"
;;
codex)
update_agent_file "$AGENTS_FILE" "Codex CLI"
;;
windsurf)
update_agent_file "$WINDSURF_FILE" "Windsurf"
;;
kilocode)
update_agent_file "$KILOCODE_FILE" "Kilo Code"
;;
auggie)
update_agent_file "$AUGGIE_FILE" "Auggie CLI"
;;
roo)
update_agent_file "$ROO_FILE" "Roo Code"
;;
codebuddy)
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
;;
qoder)
update_agent_file "$QODER_FILE" "Qoder CLI"
;;
amp)
update_agent_file "$AMP_FILE" "Amp"
;;
shai)
update_agent_file "$SHAI_FILE" "SHAI"
;;
q)
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
;;
bob)
update_agent_file "$BOB_FILE" "IBM Bob"
;;
*)
log_error "Unknown agent type '$agent_type'"
log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|shai|q|bob|qoder"
exit 1
;;
esac
}
update_all_existing_agents() {
local found_agent=false
# Check each possible agent file and update if it exists
if [[ -f "$CLAUDE_FILE" ]]; then
update_agent_file "$CLAUDE_FILE" "Claude Code"
found_agent=true
fi
if [[ -f "$GEMINI_FILE" ]]; then
update_agent_file "$GEMINI_FILE" "Gemini CLI"
found_agent=true
fi
if [[ -f "$COPILOT_FILE" ]]; then
update_agent_file "$COPILOT_FILE" "GitHub Copilot"
found_agent=true
fi
if [[ -f "$CURSOR_FILE" ]]; then
update_agent_file "$CURSOR_FILE" "Cursor IDE"
found_agent=true
fi
if [[ -f "$QWEN_FILE" ]]; then
update_agent_file "$QWEN_FILE" "Qwen Code"
found_agent=true
fi
if [[ -f "$AGENTS_FILE" ]]; then
update_agent_file "$AGENTS_FILE" "Codex/opencode"
found_agent=true
fi
if [[ -f "$WINDSURF_FILE" ]]; then
update_agent_file "$WINDSURF_FILE" "Windsurf"
found_agent=true
fi
if [[ -f "$KILOCODE_FILE" ]]; then
update_agent_file "$KILOCODE_FILE" "Kilo Code"
found_agent=true
fi
if [[ -f "$AUGGIE_FILE" ]]; then
update_agent_file "$AUGGIE_FILE" "Auggie CLI"
found_agent=true
fi
if [[ -f "$ROO_FILE" ]]; then
update_agent_file "$ROO_FILE" "Roo Code"
found_agent=true
fi
if [[ -f "$CODEBUDDY_FILE" ]]; then
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
found_agent=true
fi
if [[ -f "$SHAI_FILE" ]]; then
update_agent_file "$SHAI_FILE" "SHAI"
found_agent=true
fi
if [[ -f "$QODER_FILE" ]]; then
update_agent_file "$QODER_FILE" "Qoder CLI"
found_agent=true
fi
if [[ -f "$Q_FILE" ]]; then
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
found_agent=true
fi
if [[ -f "$BOB_FILE" ]]; then
update_agent_file "$BOB_FILE" "IBM Bob"
found_agent=true
fi
# If no agent files exist, create a default Claude file
if [[ "$found_agent" == false ]]; then
log_info "No existing agent files found, creating default Claude file..."
update_agent_file "$CLAUDE_FILE" "Claude Code"
fi
}
print_summary() {
echo
log_info "Summary of changes:"
if [[ -n "$NEW_LANG" ]]; then
echo " - Added language: $NEW_LANG"
fi
if [[ -n "$NEW_FRAMEWORK" ]]; then
echo " - Added framework: $NEW_FRAMEWORK"
fi
if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]]; then
echo " - Added database: $NEW_DB"
fi
echo
log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|codebuddy|shai|q|bob|qoder]"
}
#==============================================================================
# Main Execution
#==============================================================================
main() {
# Validate environment before proceeding
validate_environment
log_info "=== Updating agent context files for feature $CURRENT_BRANCH ==="
# Parse the plan file to extract project information
if ! parse_plan_data "$NEW_PLAN"; then
log_error "Failed to parse plan data"
exit 1
fi
# Process based on agent type argument
local success=true
if [[ -z "$AGENT_TYPE" ]]; then
# No specific agent provided - update all existing agent files
log_info "No agent specified, updating all existing agent files..."
if ! update_all_existing_agents; then
success=false
fi
else
# Specific agent provided - update only that agent
log_info "Updating specific agent: $AGENT_TYPE"
if ! update_specific_agent "$AGENT_TYPE"; then
success=false
fi
fi
# Print summary
print_summary
if [[ "$success" == true ]]; then
log_success "Agent context update completed successfully"
exit 0
else
log_error "Agent context update completed with errors"
exit 1
fi
}
# Execute main function if script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi

18
.agents/skills/VERSION Normal file
View File

@@ -0,0 +1,18 @@
# Speckit Skills Version
version: 1.1.0
release_date: 2026-01-24
## Changelog
### 1.1.0 (2026-01-24)
- New QA skills: tester, reviewer, checker
- tester: Execute tests, measure coverage, report results
- reviewer: Code review with severity levels and suggestions
- checker: Static analysis aggregation (lint, types, security)
### 1.0.0 (2026-01-24)
- Initial versioned release
- Core skills: specify, clarify, plan, tasks, implement, analyze, checklist, constitution, quizme, taskstoissues
- New skills: diff, validate, migrate, status
- All workflows enhanced with error handling and relative paths

View File

@@ -1,8 +1,9 @@
description = "Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation."
prompt = """
---
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
---
## User Input
@@ -13,8 +14,13 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Goal
## Role
You are the **Antigravity Consistency Analyst**. Your role is to identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. You act with strict adherence to the project constitution.
## 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`.
## Operating Constraints
@@ -23,11 +29,11 @@ Identify inconsistencies, duplications, ambiguities, and underspecified items ac
**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`.
## Execution Steps
### Steps
### 1. Initialize Analysis Context
Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths:
Run `../scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths:
- SPEC = FEATURE_DIR/spec.md
- PLAN = FEATURE_DIR/plan.md
@@ -185,4 +191,3 @@ Ask the user: "Would you like me to suggest concrete remediation edits for the t
## Context
{{args}}
"""

View File

@@ -0,0 +1,154 @@
---
name: speckit.checker
description: Run static analysis tools and aggregate results.
version: 1.0.0
depends-on: []
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Static Analyzer**. Your role is to run all applicable static analysis tools and provide a unified report of issues.
## Task
### Outline
Auto-detect available tools, run them, and aggregate results into a prioritized report.
### Execution Steps
1. **Detect Project Type and Tools**:
```bash
# Check for config files
ls -la | grep -E "(package.json|pyproject.toml|go.mod|Cargo.toml|pom.xml)"
# Check for linter configs
ls -la | grep -E "(eslint|prettier|pylint|golangci|rustfmt)"
```
| Config | Tools to Run |
|--------|-------------|
| `package.json` | ESLint, TypeScript, npm audit |
| `pyproject.toml` | Pylint/Ruff, mypy, bandit |
| `go.mod` | golangci-lint, go vet |
| `Cargo.toml` | clippy, cargo audit |
| `pom.xml` | SpotBugs, PMD |
2. **Run Linting**:
| Stack | Command |
|-------|---------|
| Node/TS | `npx eslint . --format json 2>/dev/null` |
| Python | `ruff check . --output-format json 2>/dev/null || pylint --output-format=json **/*.py` |
| Go | `golangci-lint run --out-format json` |
| Rust | `cargo clippy --message-format=json` |
3. **Run Type Checking**:
| Stack | Command |
|-------|---------|
| TypeScript | `npx tsc --noEmit 2>&1` |
| Python | `mypy . --no-error-summary 2>&1` |
| Go | `go build ./... 2>&1` (types are built-in) |
4. **Run Security Scanning**:
| Stack | Command |
|-------|---------|
| Node | `npm audit --json` |
| Python | `bandit -r . -f json 2>/dev/null || safety check --json` |
| Go | `govulncheck ./... 2>&1` |
| Rust | `cargo audit --json` |
5. **Aggregate and Prioritize**:
| Category | Priority |
|----------|----------|
| Security (Critical/High) | 🔴 P1 |
| Type Errors | 🟠 P2 |
| Security (Medium/Low) | 🟡 P3 |
| Lint Errors | 🟡 P3 |
| Lint Warnings | 🟢 P4 |
| Style Issues | ⚪ P5 |
6. **Generate Report**:
```markdown
# Static Analysis Report
**Date**: [timestamp]
**Project**: [name from package.json/pyproject.toml]
**Status**: CLEAN | ISSUES FOUND
## Tools Run
| Tool | Status | Issues |
|------|--------|--------|
| ESLint | ✅ | 12 |
| TypeScript | ✅ | 3 |
| npm audit | ⚠️ | 2 vulnerabilities |
## Summary by Priority
| Priority | Count |
|----------|-------|
| 🔴 P1 Critical | X |
| 🟠 P2 High | X |
| 🟡 P3 Medium | X |
| 🟢 P4 Low | X |
## Issues
### 🔴 P1: Security Vulnerabilities
| Package | Severity | Issue | Fix |
|---------|----------|-------|-----|
| lodash | HIGH | Prototype Pollution | Upgrade to 4.17.21 |
### 🟠 P2: Type Errors
| File | Line | Error |
|------|------|-------|
| src/api.ts | 45 | Type 'string' is not assignable to type 'number' |
### 🟡 P3: Lint Issues
| File | Line | Rule | Message |
|------|------|------|---------|
| src/utils.ts | 12 | no-unused-vars | 'foo' is defined but never used |
## Quick Fixes
```bash
# Fix security issues
npm audit fix
# Auto-fix lint issues
npx eslint . --fix
```
## Recommendations
1. **Immediate**: Fix P1 security issues
2. **Before merge**: Fix P2 type errors
3. **Tech debt**: Address P3/P4 lint issues
```
7. **Output**:
- Display report
- Exit with non-zero if P1 or P2 issues exist
## Operating Principles
- **Run Everything**: Don't skip tools, aggregate all results
- **Be Fast**: Run tools in parallel when possible
- **Be Actionable**: Every issue should have a clear fix path
- **Don't Duplicate**: Dedupe issues found by multiple tools
- **Respect Configs**: Honor project's existing linter configs

View File

@@ -1,7 +1,5 @@
description = "Generate a custom checklist for the current feature based on user requirements."
prompt = """
---
name: speckit.checklist
description: Generate a custom checklist for the current feature based on user requirements.
---
@@ -34,9 +32,15 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Execution Steps
## Role
1. **Setup**: Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json` from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS list.
You are the **Antigravity Quality Gatekeeper**. Your role is to validate the quality of requirements by generating "Unit Tests for English"—checklists that ensure specifications are complete, clear, consistent, and measurable. You don't test the code; you test the documentation that defines it.
## Task
### Execution Steps
1. **Setup**: Run `../scripts/bash/check-prerequisites.sh --json` from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS list.
- All file paths must be absolute.
- 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").
@@ -178,7 +182,7 @@ You **MUST** consider the user input before proceeding (if not empty).
- If no ID system exists: "Is a requirement & acceptance criteria ID scheme established? [Traceability]"
**Surface & Resolve Issues** (Requirements Quality Problems):
Ask questions about the requirements themselves:
- Ask questions about the requirements themselves:
- Ambiguities: "Is the term 'fast' quantified with specific metrics? [Ambiguity, Spec §NFR-1]"
- Conflicts: "Do navigation requirements conflict between §FR-10 and §FR-10a? [Conflict]"
- Assumptions: "Is the assumption of 'always available podcast API' validated? [Assumption]"
@@ -206,7 +210,7 @@ You **MUST** consider the user input before proceeding (if not empty).
- ✅ "Are [edge cases/scenarios] addressed in requirements?"
- ✅ "Does the spec define [missing aspect]?"
6. **Structure Reference**: Generate the checklist following the canonical template in `.specify/templates/checklist-template.md` for title, meta section, category headings, and ID formatting. If template is unavailable, use: H1 title, purpose/created meta lines, `##` category sections containing `- [ ] CHK### <requirement item>` lines with globally incrementing IDs starting at CHK001.
b. **Structure Reference**: Generate the checklist following the canonical template in `templates/checklist-template.md` for title, meta section, category headings, and ID formatting. If template is unavailable, use: H1 title, purpose/created meta lines, `##` category sections containing `- [ ] CHK### <requirement item>` lines with globally incrementing IDs starting at CHK001.
7. **Report**: Output full path to created checklist, item count, and remind user that each run creates a new file. Summarize:
- Focus areas selected
@@ -295,4 +299,3 @@ Sample items:
- Correct: Validation of requirement quality
- Wrong: "Does it do X?"
- Correct: "Is X clearly specified?"
"""

View File

@@ -0,0 +1,40 @@
# [CHECKLIST TYPE] Checklist: [FEATURE NAME]
**Purpose**: [Brief description of what this checklist covers]
**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.
<!--
============================================================================
IMPORTANT: The checklist items below are SAMPLE ITEMS for illustration only.
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
- Implementation details from tasks.md
DO NOT keep these sample items in the generated checklist file.
============================================================================
-->
## [Category 1]
- [ ] CHK001 First checklist item with clear action
- [ ] CHK002 Second checklist item
- [ ] CHK003 Third checklist item
## [Category 2]
- [ ] CHK004 Another category item
- [ ] CHK005 Item with specific criteria
- [ ] CHK006 Final item in this category
## Notes
- Check items off as completed: `[x]`
- Add comments or findings inline
- Link to relevant resources or documentation
- Items are numbered sequentially for easy reference

View File

@@ -1,8 +1,9 @@
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."
prompt = """
---
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
handoffs:
- label: Build Technical Plan
agent: speckit.plan
@@ -17,7 +18,13 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Outline
## Role
You are the **Antigravity Ambiguity Buster**. Your role is to interrogate specifications for logical gaps, missing constraints, or vague requirements. You resolve these via structured questioning to minimize rework risk.
## Task
### Outline
Goal: Detect and reduce ambiguity or missing decision points in the active feature specification and record the clarifications directly in the spec file.
@@ -25,7 +32,7 @@ Note: This clarification workflow is expected to run (and be completed) BEFORE i
Execution steps:
1. Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly` from repo root **once** (combined `--json --paths-only` mode / `-Json -PathsOnly`). Parse minimal JSON payload fields:
1. Run `../scripts/bash/check-prerequisites.sh --json --paths-only` from repo root **once** (combined `--json --paths-only` mode / `-Json -PathsOnly`). Parse minimal JSON payload fields:
- `FEATURE_DIR`
- `FEATURE_SPEC`
- (Optionally capture `IMPL_PLAN`, `TASKS` for future chained flows.)
@@ -182,4 +189,3 @@ Behavior rules:
- If quota reached with unresolved high-impact categories remaining, explicitly flag them under Deferred with rationale.
Context for prioritization: {{args}}
"""

View File

@@ -1,7 +1,5 @@
description = "Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync."
prompt = """
---
name: speckit.constitution
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
handoffs:
- label: Build Specification
@@ -17,13 +15,19 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Outline
## Role
You are the **Antigravity Governance Architect**. Your role is to establish and maintain the project's "Source of Law"—the constitution. You ensure that all project principles, standards, and non-negotiables are clearly documented and kept in sync across all templates and workflows.
## Task
### Outline
You are updating the project constitution at `.specify/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts.
Follow this execution flow:
1. Load the existing constitution template at `.specify/memory/constitution.md`.
1. Load the existing constitution template at `memory/constitution.md`.
- Identify every placeholder token of the form `[ALL_CAPS_IDENTIFIER]`.
**IMPORTANT**: The user might require less or more principles than the ones used in the template. If a number is specified, respect that - follow the general template. You will update the doc accordingly.
@@ -83,4 +87,3 @@ If the user supplies partial updates (e.g., only one principle revision), still
If critical info missing (e.g., ratification date truly unknown), insert `TODO(<FIELD_NAME>): explanation` and include in the Sync Impact Report under deferred items.
Do not create a new template; always operate on the existing `.specify/memory/constitution.md` file.
"""

View File

@@ -0,0 +1,81 @@
---
name: speckit.diff
description: Compare two versions of a spec or plan to highlight changes.
version: 1.0.0
depends-on: []
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Diff Analyst**. Your role is to compare specification/plan versions and produce clear, actionable change summaries.
## Task
### Outline
Compare two versions of a specification artifact and produce a structured diff report.
### Execution Steps
1. **Parse Arguments**:
- If user provides two file paths: Compare those files directly
- If user provides one file path: Compare current version with git HEAD
- If no arguments: Use `check-prerequisites.sh` to find current feature's spec.md and compare with HEAD
2. **Load Files**:
```bash
# For git comparison
git show HEAD:<relative-path> > /tmp/old_version.md
```
- Read both versions into memory
3. **Semantic Diff Analysis**:
Analyze changes by section:
- **Added**: New sections, requirements, or criteria
- **Removed**: Deleted content
- **Modified**: Changed wording or values
- **Moved**: Reorganized content (same meaning, different location)
4. **Generate Report**:
```markdown
# Diff Report: [filename]
**Compared**: [version A] → [version B]
**Date**: [timestamp]
## Summary
- X additions, Y removals, Z modifications
## Changes by Section
### [Section Name]
| Type | Content | Impact |
|------|---------|--------|
| + Added | [new text] | [what this means] |
| - Removed | [old text] | [what this means] |
| ~ Modified | [before] → [after] | [what this means] |
## Risk Assessment
- Breaking changes: [list any]
- Scope changes: [list any]
```
5. **Output**:
- Display report in terminal (do NOT write to file unless requested)
- Offer to save report to `FEATURE_DIR/diffs/[timestamp].md`
## Operating Principles
- **Be Precise**: Quote exact text changes
- **Highlight Impact**: Explain what each change means for implementation
- **Flag Breaking Changes**: Any change that invalidates existing work
- **Ignore Whitespace**: Focus on semantic changes, not formatting

View File

@@ -0,0 +1,248 @@
---
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
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Master Builder**. Your role is to execute the implementation plan with precision, processing tasks from `tasks.md` and ensuring that the final codebase aligns perfectly with the specification, plan, and quality standards.
**CORE OBJECTIVE:** Fix bugs and implement features with **ZERO REGRESSION**.
**YOUR MOTTO:** "Measure twice, cut once. If you can't prove it's broken, don't fix it."
---
## 🛡️ IRONCLAD PROTOCOLS (Non-Negotiable)
These protocols MUST be followed for EVERY task before any production code modification:
### Protocol 1: Blast Radius Analysis
**BEFORE** writing a single line of production code modification, you MUST:
1. **Read**: Read the target file(s) to understand current implementation.
2. **Trace**: Use `grep` or search tools to find ALL other files importing or using the function/class you intend to modify.
3. **Report**: Output a precise list:
```
🔍 BLAST RADIUS ANALYSIS
─────────────────────────
Modifying: `[Function/Class X]` in `[file.ts]`
Affected files: [A.ts, B.ts, C.ts]
Risk Level: [LOW (<3 files) | MEDIUM (3-5 files) | HIGH (>5 files)]
```
4. **Decide**: If > 2 files are affected, **DO NOT MODIFY inline**. Trigger **Protocol 2 (Strangler Pattern)**.
### Protocol 2: Strangler Pattern (Immutable Core)
If a file is critical, complex, or has high dependencies (>2 affected files):
1. **DO NOT EDIT** the existing function inside the old file.
2. **CREATE** a new file/module (e.g., `feature_v2.ts` or `utils_patch.ts`).
3. **IMPLEMENT** the improved logic there.
4. **SWITCH** the imports in the consuming files one by one.
5. **ANNOUNCE**: "Applying Strangler Pattern to avoid regression."
*Benefit: If it breaks, we simply revert the import, not the whole logic.*
### Protocol 3: Reproduction Script First (TDD)
You are **FORBIDDEN** from fixing a bug or implementing a feature without evidence:
1. Create a temporary script `repro_task_[id].ts` (or .js/.py/.go based on stack).
2. This script MUST:
- For bugs: **FAIL** when run against the current code (demonstrating the bug).
- For features: **FAIL** when run against current code (feature doesn't exist).
3. Run it and show the failure output.
4. **ONLY THEN**, implement the fix/feature.
5. Run the script again to prove it passes.
6. Delete the temporary script OR convert it to a permanent test.
### Protocol 4: Context Anchoring
At the start of execution and after every 3 modifications:
1. Run `tree -L 2` (or equivalent) to visualize the file structure.
2. Update `ARCHITECTURE.md` if it exists, or create it to reflect the current reality.
---
## Task Execution
### Outline
1. Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. 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. **Check checklists status** (if FEATURE_DIR/checklists/ exists):
- Scan all checklist files in the checklists/ directory
- For each checklist, count:
- Total items: All lines matching `- [ ]` or `- [X]` or `- [x]`
- Completed items: Lines matching `- [X]` or `- [x]`
- Incomplete items: Lines matching `- [ ]`
- Create a status table:
```text
| Checklist | Total | Completed | Incomplete | Status |
|-----------|-------|-----------|------------|--------|
| ux.md | 12 | 12 | 0 | ✓ PASS |
| test.md | 8 | 5 | 3 | ✗ FAIL |
| security.md | 6 | 6 | 0 | ✓ PASS |
```
- Calculate overall status:
- **PASS**: All checklists have 0 incomplete items
- **FAIL**: One or more checklists have incomplete items
- **If any checklist is incomplete**:
- Display the table with incomplete item counts
- **STOP** and ask: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
- Wait for user response before continuing
- If user says "no" or "wait" or "stop", halt execution
- If user says "yes" or "proceed" or "continue", proceed to step 3
- **If all checklists are complete**:
- Display the table showing all checklists passed
- Automatically proceed to step 3
3. Load and analyze the implementation context:
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
- **REQUIRED**: Read plan.md for tech stack, architecture, and file structure
- **IF EXISTS**: Read data-model.md for entities and relationships
- **IF EXISTS**: Read contracts/ for API specifications and test requirements
- **IF EXISTS**: Read research.md for technical decisions and constraints
- **IF EXISTS**: Read quickstart.md for integration scenarios
4. **Context Anchoring (Protocol 4)**:
- Run `tree -L 2` to visualize the current file structure
- Document the initial state before any modifications
5. **Project Setup Verification**:
- **REQUIRED**: Create/verify ignore files based on actual project setup:
**Detection & Creation Logic**:
- Check if the following command succeeds to determine if the repository is a git repo (create/verify .gitignore if so):
```sh
git rev-parse --git-dir 2>/dev/null
```
- Check if Dockerfile* exists or Docker in plan.md → create/verify .dockerignore
- Check if .eslintrc* exists → create/verify .eslintignore
- Check if eslint.config.* exists → ensure the config's `ignores` entries cover required patterns
- Check if .prettierrc* exists → create/verify .prettierignore
- Check if .npmrc or package.json exists → create/verify .npmignore (if publishing)
- Check if terraform files (*.tf) exist → create/verify .terraformignore
- Check if .helmignore needed (helm charts present) → create/verify .helmignore
**If ignore file already exists**: Verify it contains essential patterns, append missing critical patterns only
**If ignore file missing**: Create with full pattern set for detected technology
**Common Patterns by Technology** (from plan.md tech stack):
- **Node.js/JavaScript/TypeScript**: `node_modules/`, `dist/`, `build/`, `*.log`, `.env*`
- **Python**: `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `dist/`, `*.egg-info/`
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
**Tool-Specific Patterns**:
- **Docker**: `node_modules/`, `.git/`, `Dockerfile*`, `.dockerignore`, `*.log*`, `.env*`, `coverage/`
- **ESLint**: `node_modules/`, `dist/`, `build/`, `coverage/`, `*.min.js`
- **Prettier**: `node_modules/`, `dist/`, `build/`, `coverage/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
- **Terraform**: `.terraform/`, `*.tfstate*`, `*.tfvars`, `.terraform.lock.hcl`
- **Kubernetes/k8s**: `*.secret.yaml`, `secrets/`, `.kube/`, `kubeconfig*`, `*.key`, `*.crt`
6. Parse tasks.md structure and extract:
- **Task phases**: Setup, Tests, Core, Integration, Polish
- **Task dependencies**: Sequential vs parallel execution rules
- **Task details**: ID, description, file paths, parallel markers [P]
- **Execution flow**: Order and dependency requirements
7. **Execute implementation following the task plan with Ironclad Protocols**:
**For EACH task**, follow this sequence:
a. **Blast Radius Analysis (Protocol 1)**:
- Identify all files that will be modified
- Run `grep` to find all dependents
- Report the blast radius
b. **Strategy Decision**:
- If LOW risk (≤2 affected files): Proceed with inline modification
- If MEDIUM/HIGH risk (>2 files): Apply Strangler Pattern (Protocol 2)
c. **Reproduction Script (Protocol 3)**:
- Create `repro_task_[ID].ts` that demonstrates expected behavior
- Run it to confirm current state (should fail for new features, or fail for bugs)
d. **Implementation**:
- Execute the task according to plan
- **Phase-by-phase execution**: Complete each phase before moving to the next
- **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
- **File-based coordination**: Tasks affecting the same files must run sequentially
e. **Verification**:
- Run the reproduction script again (should now pass)
- Run existing tests to ensure no regression
- If any test fails: **STOP** and report the regression
f. **Cleanup**:
- Delete temporary repro scripts OR convert to permanent tests
- Mark task as complete `[X]` in tasks.md
8. **Progress tracking and error handling**:
- Report progress after each completed task with this format:
```
✅ TASK [ID] COMPLETE
─────────────────────
Modified files: [list]
Tests passed: [count]
Blast radius: [LOW/MEDIUM/HIGH]
```
- Halt execution if any non-parallel task fails
- For parallel tasks [P], continue with successful tasks, report failed ones
- Provide clear error messages with context for debugging
- Suggest next steps if implementation cannot proceed
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
9. **Context Re-anchoring (every 3 tasks)**:
- Run `tree -L 2` to verify file structure
- Update ARCHITECTURE.md if structure has changed
10. **Completion validation**:
- Verify all required tasks are completed
- Check that implemented features match the original specification
- Validate that tests pass and coverage meets requirements
- Confirm the implementation follows the technical plan
- Report final status with summary of completed work
---
## 🚫 Anti-Hallucination Rules
1. **No Magic Imports:** Never import a library or file without checking `ls` or `package.json` first.
2. **Strict Diff-Only:** When modifying existing files, use minimal edits.
3. **Stop & Ask:** If you find yourself editing more than 3 files for a "simple fix," **STOP**. You are likely cascading a regression. Ask for strategic guidance.
---
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.

View File

@@ -0,0 +1,106 @@
---
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: []
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Migration Specialist**. Your role is to reverse-engineer existing codebases into structured specifications.
## Task
### Outline
Analyze an existing codebase and generate speckit artifacts (spec.md, plan.md, tasks.md) that document what currently exists.
### Execution Steps
1. **Parse Arguments**:
- `--path <dir>`: Directory to analyze (default: current repo root)
- `--feature <name>`: Feature name for output directory
- `--depth <n>`: Analysis depth (1=overview, 2=detailed, 3=exhaustive)
2. **Codebase Discovery**:
```bash
# Get project structure
tree -L 3 --dirsfirst -I 'node_modules|.git|dist|build' > /tmp/structure.txt
# Find key files
find . -name "*.md" -o -name "package.json" -o -name "*.config.*" | head -50
```
3. **Analyze Architecture**:
- Identify framework/stack from config files
- Map directory structure to components
- Find entry points (main, index, app)
- Identify data models/entities
- Map API endpoints (if applicable)
4. **Generate spec.md** (reverse-engineered):
```markdown
# [Feature Name] - Specification (Migrated)
> This specification was auto-generated from existing code.
> Review and refine before using for future development.
## Overview
[Inferred from README, comments, and code structure]
## Functional Requirements
[Extracted from existing functionality]
## Key Entities
[From data models, schemas, types]
```
5. **Generate plan.md** (reverse-engineered):
```markdown
# [Feature Name] - Technical Plan (Migrated)
## Current Architecture
[Documented from codebase analysis]
## Technology Stack
[From package.json, imports, configs]
## Component Map
[Directory → responsibility mapping]
```
6. **Generate tasks.md** (completion status):
```markdown
# [Feature Name] - Tasks (Migrated)
All tasks marked [x] represent existing implemented functionality.
Tasks marked [ ] are inferred gaps or TODOs found in code.
## Existing Implementation
- [x] [Component A] - Implemented in `src/componentA/`
- [x] [Component B] - Implemented in `src/componentB/`
## Identified Gaps
- [ ] [Missing tests for X]
- [ ] [TODO comment at Y]
```
7. **Output**:
- Create feature directory: `.specify/features/[feature-name]/`
- Write all three files
- Report summary with confidence scores
## Operating Principles
- **Don't Invent**: Only document what exists, mark uncertainties as [INFERRED]
- **Preserve Intent**: Use code comments and naming to understand purpose
- **Flag TODOs**: Any TODO/FIXME/HACK in code becomes an open task
- **Be Conservative**: When unsure, ask rather than assume

View File

@@ -1,8 +1,9 @@
description = "Execute the implementation planning workflow using the plan template to generate design artifacts."
prompt = """
---
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
handoffs:
- label: Create Tasks
agent: speckit.tasks
@@ -21,11 +22,17 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Outline
## Role
1. **Setup**: Run `.specify/scripts/powershell/setup-plan.ps1 -Json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. 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").
You are the **Antigravity System Architect**. Your role is to bridge the gap between functional specifications and technical implementation. You design data models, define API contracts, and perform technical research to ensure a robust and scalable architecture.
2. **Load context**: Read FEATURE_SPEC and `.specify/memory/constitution.md`. Load IMPL_PLAN template (already copied).
## Task
### Outline
1. **Setup**: Run `../scripts/bash/setup-plan.sh --json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. 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 context**: Read FEATURE_SPEC and `.specify/memory/constitution.md`. Load IMPL_PLAN template from `templates/plan-template.md`.
3. **Execute plan workflow**: Follow the structure in IMPL_PLAN template to:
- Fill Technical Context (mark unknowns as "NEEDS CLARIFICATION")
@@ -78,7 +85,7 @@ You **MUST** consider the user input before proceeding (if not empty).
- Output OpenAPI/GraphQL schema to `/contracts/`
3. **Agent context update**:
- Run `.specify/scripts/powershell/update-agent-context.ps1 -AgentType gemini`
- Run `../scripts/bash/update-agent-context.sh gemini`
- These scripts detect which AI agent is in use
- Update the appropriate agent-specific context file
- Add only new technology from current plan
@@ -90,4 +97,3 @@ You **MUST** consider the user input before proceeding (if not empty).
- Use absolute paths
- ERROR on gate failures or unresolved clarifications
"""

View File

@@ -0,0 +1,28 @@
# [PROJECT NAME] Development Guidelines
Auto-generated from all feature plans. Last updated: [DATE]
## Active Technologies
[EXTRACTED FROM ALL PLAN.MD FILES]
## Project Structure
```text
[ACTUAL STRUCTURE FROM PLANS]
```
## Commands
[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES]
## Code Style
[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE]
## Recent Changes
[LAST 3 FEATURES AND WHAT THEY ADDED]
<!-- MANUAL ADDITIONS START -->
<!-- MANUAL ADDITIONS END -->

View File

@@ -0,0 +1,104 @@
# Implementation Plan: [FEATURE]
**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.
## Summary
[Extract from feature spec: primary requirement + technical approach from research]
## Technical Context
<!--
ACTION REQUIRED: Replace the content in this section with the technical details
for the project. The structure here is presented in advisory capacity to guide
the iteration process.
-->
**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
**Target Platform**: [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION]
**Project Type**: [single/web/mobile - determines source structure]
**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
**Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
[Gates determined based on constitution file]
## Project Structure
### Documentation (this feature)
```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)
```
### Source Code (repository root)
<!--
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
for this feature. Delete unused options and expand the chosen structure with
real paths (e.g., apps/admin, packages/something). The delivered plan must
not include Option labels.
-->
```text
# [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
src/
├── models/
├── services/
├── cli/
└── lib/
tests/
├── contract/
├── integration/
└── unit/
# [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected)
backend/
├── src/
│ ├── models/
│ ├── services/
│ └── api/
└── tests/
frontend/
├── src/
│ ├── components/
│ ├── pages/
│ └── services/
└── tests/
# [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected)
api/
└── [same as backend above]
ios/ or android/
└── [platform-specific structure: feature modules, UI flows, platform tests]
```
**Structure Decision**: [Document the selected structure and reference the real
directories captured above]
## Complexity Tracking
> **Fill ONLY if Constitution Check has violations that must be justified**
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |

View File

@@ -0,0 +1,65 @@
---
name: speckit.quizme
description: Challenge the specification with Socratic questioning to identify logical gaps, unhandled edge cases, and robustness issues.
handoffs:
- label: Clarify Spec Requirements
agent: speckit.clarify
prompt: Clarify specification requirements
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Red Teamer**. Your role is to play the "Socratic Teacher" and challenge specifications for logical fallacies, naive assumptions, and happy-path bias. You find the edge cases that others miss and force robustness into the design.
## Task
### 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.
Execution steps:
1. **Setup**: Run `../scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR.
2. **Load Spec**: Read `spec.md` and `plan.md` (if exists).
3. **Analyze for Weaknesses** (Internal Thought Process):
- Identify "Happy Path" assumptions (e.g., "User clicks button and saves").
- Look for temporal/state gaps (e.g., "What if the user clicks twice?", "What if the network fails mid-save?").
- Challenge business logic (e.g., "You allow deleting users, but what happens to their data?").
- Challenge security (e.g., "You rely on client-side validation here, but what if I curl the API?").
4. **The Quiz Loop**:
- Present 3-5 challenging scenarios *one by one*.
- Format:
> **Scenario**: [Describe a plausible edge case or failure]
> **Current Spec**: [Quote where the spec implies behavior or is silent]
> **The Quiz**: What should the system do here?
- Wait for user answer.
- Critique the answer:
- If user says "It errors", ask "What error? To whom? Logged where?"
- If user says "It shouldn't happen", ask "How do you prevent it?"
5. **Capture & Refine**:
- For each resolved scenario, generate a new requirement or edge case bullet.
- Ask user for permission to add it to `spec.md`.
- On approval, append to `Edge Cases` or `Requirements` section.
6. **Completion**:
- Report number of scenarios covered.
- List new requirements added.
## Operating Principles
- **Be a Skeptic**: Don't assume the happy path works.
- **Focus on "When" and "If"**: When high load, If network drops, When concurrent edits.
- **Don't be annoying**: Focus on *critical* flaws, not nitpicks.

View File

@@ -0,0 +1,136 @@
---
name: speckit.reviewer
description: Perform code review with actionable feedback and suggestions.
version: 1.0.0
depends-on: []
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Code Reviewer**. Your role is to perform thorough code reviews, identify issues, and provide constructive, actionable feedback.
## Task
### Outline
Review code changes and provide structured feedback with severity levels.
### Execution Steps
1. **Determine Review Scope**:
- If user provides file paths: Review those files
- If user says "staged" or no args: Review git staged changes
- If user says "branch": Compare current branch to main/master
```bash
# Get staged changes
git diff --cached --name-only
# Get branch changes
git diff main...HEAD --name-only
```
2. **Load Files for Review**:
- Read each file in scope
- For diffs, focus on changed lines with context
3. **Review Categories**:
| Category | What to Check |
|----------|--------------|
| **Correctness** | Logic errors, off-by-one, null handling |
| **Security** | SQL injection, XSS, secrets in code |
| **Performance** | N+1 queries, unnecessary loops, memory leaks |
| **Maintainability** | Complexity, duplication, naming |
| **Best Practices** | Error handling, logging, typing |
| **Style** | Consistency, formatting (if no linter) |
4. **Analyze Each File**:
For each file, check:
- Does the code do what it claims?
- Are edge cases handled?
- Is error handling appropriate?
- Are there security concerns?
- Is the code testable?
- Is the naming clear and consistent?
5. **Severity Levels**:
| Level | Meaning | Block Merge? |
|-------|---------|--------------|
| 🔴 CRITICAL | Security issue, data loss risk | Yes |
| 🟠 HIGH | Bug, logic error | Yes |
| 🟡 MEDIUM | Code smell, maintainability | Maybe |
| 🟢 LOW | Style, minor improvement | No |
| 💡 SUGGESTION | Nice-to-have, optional | No |
6. **Generate Review Report**:
```markdown
# Code Review Report
**Date**: [timestamp]
**Scope**: [files reviewed]
**Overall**: APPROVE | REQUEST CHANGES | NEEDS DISCUSSION
## Summary
| Severity | Count |
|----------|-------|
| 🔴 Critical | X |
| 🟠 High | X |
| 🟡 Medium | X |
| 🟢 Low | X |
| 💡 Suggestions | X |
## Findings
### 🔴 CRITICAL: SQL Injection Risk
**File**: `src/db/queries.ts:45`
**Code**:
```typescript
const query = `SELECT * FROM users WHERE id = ${userId}`;
```
**Issue**: User input directly concatenated into SQL query
**Fix**: Use parameterized queries:
```typescript
const query = 'SELECT * FROM users WHERE id = $1';
await db.query(query, [userId]);
```
### 🟡 MEDIUM: Complex Function
**File**: `src/auth/handler.ts:120`
**Issue**: Function has cyclomatic complexity of 15
**Suggestion**: Extract into smaller functions
## What's Good
- Clear naming conventions
- Good test coverage
- Proper TypeScript types
## Recommended Actions
1. **Must fix before merge**: [critical/high items]
2. **Should address**: [medium items]
3. **Consider for later**: [low/suggestions]
```
7. **Output**:
- Display report
- If CRITICAL or HIGH issues: Recommend blocking merge
## Operating Principles
- **Be Constructive**: Every criticism should have a fix suggestion
- **Be Specific**: Quote exact code, provide exact line numbers
- **Be Balanced**: Mention what's good, not just what's wrong
- **Prioritize**: Focus on real issues, not style nitpicks
- **Be Educational**: Explain WHY something is an issue

View File

@@ -1,7 +1,5 @@
description = "Create or update the feature specification from a natural language feature description."
prompt = """
---
name: speckit.specify
description: Create or update the feature specification from a natural language feature description.
handoffs:
- label: Build Technical Plan
@@ -21,7 +19,13 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Outline
## Role
You are the **Antigravity Domain Scribe**. Your role is to translate natural language feature descriptions into highly structured, high-quality feature specifications (`spec.md`). You ensure clarity, testability, and alignment with the project's success criteria.
## Task
### 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.
@@ -56,10 +60,10 @@ Given that feature description, do this:
- Find the highest number N
- Use N+1 for the new branch number
d. Run the script `.specify/scripts/powershell/create-new-feature.ps1 -Json "{{args}}"` with the calculated number and short-name:
d. Run the script `../scripts/bash/create-new-feature.sh --json "{{args}}"` with the calculated number and short-name:
- Pass `--number N+1` and `--short-name "your-short-name"` along with the feature description
- Bash example: `.specify/scripts/powershell/create-new-feature.ps1 -Json "{{args}}" --json --number 5 --short-name "user-auth" "Add user authentication"`
- PowerShell example: `.specify/scripts/powershell/create-new-feature.ps1 -Json "{{args}}" -Json -Number 5 -ShortName "user-auth" "Add user authentication"`
- Bash example: `.specify/scripts/bash/create-new-feature.sh --json "{{args}}" --json --number 5 --short-name "user-auth" "Add user authentication"`
- PowerShell example: `.specify/scripts/bash/create-new-feature.sh --json "{{args}}" -Json -Number 5 -ShortName "user-auth" "Add user authentication"`
**IMPORTANT**:
- Check all three sources (remote branches, local branches, specs directories) to find the highest number
@@ -70,7 +74,7 @@ Given that feature description, do this:
- The JSON output will contain BRANCH_NAME and SPEC_FILE paths
- 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")
3. Load `.specify/templates/spec-template.md` to understand required sections.
3. Load `templates/spec-template.md` to understand required sections.
4. Follow this execution flow:
@@ -258,4 +262,3 @@ Success criteria must be:
- "Database can handle 1000 TPS" (implementation detail, use user-facing metric)
- "React components render efficiently" (framework-specific)
- "Redis cache hit rate above 80%" (technology-specific)
"""

View File

@@ -0,0 +1,115 @@
# Feature Specification: [FEATURE NAME]
**Feature Branch**: `[###-feature-name]`
**Created**: [DATE]
**Status**: Draft
**Input**: User description: "$ARGUMENTS"
## User Scenarios & Testing *(mandatory)*
<!--
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
you should still have a viable MVP (Minimum Viable Product) that delivers value.
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
Think of each story as a standalone slice of functionality that can be:
- Developed independently
- Tested independently
- Deployed independently
- Demonstrated to users independently
-->
### User Story 1 - [Brief Title] (Priority: P1)
[Describe this user journey in plain language]
**Why this priority**: [Explain the value and why it has this priority level]
**Independent Test**: [Describe how this can be tested independently - e.g., "Can be fully tested by [specific action] and delivers [specific value]"]
**Acceptance Scenarios**:
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
2. **Given** [initial state], **When** [action], **Then** [expected outcome]
---
### User Story 2 - [Brief Title] (Priority: P2)
[Describe this user journey in plain language]
**Why this priority**: [Explain the value and why it has this priority level]
**Independent Test**: [Describe how this can be tested independently]
**Acceptance Scenarios**:
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
---
### User Story 3 - [Brief Title] (Priority: P3)
[Describe this user journey in plain language]
**Why this priority**: [Explain the value and why it has this priority level]
**Independent Test**: [Describe how this can be tested independently]
**Acceptance Scenarios**:
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
---
[Add more user stories as needed, each with an assigned priority]
### Edge Cases
<!--
ACTION REQUIRED: The content in this section represents placeholders.
Fill them out with the right edge cases.
-->
- What happens when [boundary condition]?
- How does system handle [error scenario]?
## Requirements *(mandatory)*
<!--
ACTION REQUIRED: The content in this section represents placeholders.
Fill them out with the right functional requirements.
-->
### Functional Requirements
- **FR-001**: System MUST [specific capability, e.g., "allow users to create accounts"]
- **FR-002**: System MUST [specific capability, e.g., "validate email addresses"]
- **FR-003**: Users MUST be able to [key interaction, e.g., "reset their password"]
- **FR-004**: System MUST [data requirement, e.g., "persist user preferences"]
- **FR-005**: System MUST [behavior, e.g., "log all security events"]
*Example of marking unclear requirements:*
- **FR-006**: System MUST authenticate users via [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?]
- **FR-007**: System MUST retain user data for [NEEDS CLARIFICATION: retention period not specified]
### Key Entities *(include if feature involves data)*
- **[Entity 1]**: [What it represents, key attributes without implementation]
- **[Entity 2]**: [What it represents, relationships to other entities]
## Success Criteria *(mandatory)*
<!--
ACTION REQUIRED: Define measurable success criteria.
These must be technology-agnostic and measurable.
-->
### Measurable Outcomes
- **SC-001**: [Measurable metric, e.g., "Users can complete account creation in under 2 minutes"]
- **SC-002**: [Measurable metric, e.g., "System handles 1000 concurrent users without degradation"]
- **SC-003**: [User satisfaction metric, e.g., "90% of users successfully complete primary task on first attempt"]
- **SC-004**: [Business metric, e.g., "Reduce support tickets related to [X] by 50%"]

View File

@@ -0,0 +1,107 @@
---
name: speckit.status
description: Display a dashboard showing feature status, completion percentage, and blockers.
version: 1.0.0
depends-on: []
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Status Reporter**. Your role is to provide clear, actionable status updates on project progress.
## Task
### Outline
Generate a dashboard view of all features and their completion status.
### Execution Steps
1. **Discover Features**:
```bash
# Find all feature directories
find .specify/features -maxdepth 1 -type d 2>/dev/null || echo "No features found"
```
2. **For Each Feature, Gather Metrics**:
| Artifact | Check | Metric |
|----------|-------|--------|
| spec.md | Exists? | Has [NEEDS CLARIFICATION]? |
| plan.md | Exists? | All sections complete? |
| tasks.md | Exists? | Count [x] vs [ ] vs [/] |
| checklists/*.md | All items checked? | Checklist completion % |
3. **Calculate Completion**:
```
Phase 1 (Specify): spec.md exists & no clarifications needed
Phase 2 (Plan): plan.md exists & complete
Phase 3 (Tasks): tasks.md exists
Phase 4 (Implement): tasks.md completion %
Phase 5 (Validate): validation-report.md exists with PASS
```
4. **Identify Blockers**:
- [NEEDS CLARIFICATION] markers
- [ ] tasks with no progress
- Failed checklist items
- Missing dependencies
5. **Generate Dashboard**:
```markdown
# Speckit Status Dashboard
**Generated**: [timestamp]
**Total Features**: X
## Overview
| Feature | Phase | Progress | Blockers | Next Action |
|---------|-------|----------|----------|-------------|
| auth-system | Implement | 75% | 0 | Complete remaining tasks |
| payment-flow | Plan | 40% | 2 | Resolve clarifications |
## Feature Details
### [Feature Name]
```
Spec: ████████░░ 80%
Plan: ██████████ 100%
Tasks: ██████░░░░ 60%
```
**Blockers**:
- [ ] Clarification needed: "What payment providers?"
**Recent Activity**:
- Last modified: [date]
- Files changed: [list]
---
## Summary
- Features Ready for Implementation: X
- Features Blocked: Y
- Overall Project Completion: Z%
```
6. **Output**:
- Display in terminal
- Optionally write to `.specify/STATUS.md`
## Operating Principles
- **Be Current**: Always read latest file state
- **Be Visual**: Use progress bars and tables
- **Be Actionable**: Every status should have a "next action"
- **Be Fast**: Cache nothing, always recalculate

View File

@@ -1,8 +1,9 @@
description = "Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts."
prompt = """
---
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
handoffs:
- label: Analyze For Consistency
agent: speckit.analyze
@@ -22,9 +23,15 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Outline
## Role
1. **Setup**: Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. 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").
You are the **Antigravity Execution Strategist**. Your role is to deconstruct complex technical plans into atomic, dependency-ordered tasks. You organize work into user-story-driven phases to ensure incremental delivery and high observability.
## Task
### Outline
1. **Setup**: Run `../scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. 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 design documents**: Read from FEATURE_DIR:
- **Required**: plan.md (tech stack, libraries, structure), spec.md (user stories with priorities)
@@ -42,7 +49,7 @@ You **MUST** consider the user input before proceeding (if not empty).
- Create parallel execution examples per user story
- Validate task completeness (each user story has all needed tasks, independently testable)
4. **Generate tasks.md**: Use `.specify.specify/templates/tasks-template.md` as structure, fill with:
4. **Generate tasks.md**: Use `templates/tasks-template.md` as structure, fill with:
- Correct feature name from plan.md
- Phase 1: Setup tasks (project initialization)
- Phase 2: Foundational tasks (blocking prerequisites for all user stories)
@@ -138,4 +145,3 @@ Every task MUST strictly follow this format:
- Within each story: Tests (if requested) → Models → Services → Endpoints → Integration
- Each phase should be a complete, independently testable increment
- **Final Phase**: Polish & Cross-Cutting Concerns
"""

View File

@@ -0,0 +1,251 @@
---
description: "Task list template for feature implementation"
---
# Tasks: [FEATURE NAME]
**Input**: Design documents from `/specs/[###-feature-name]/`
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
**Tests**: The examples below include test tasks. Tests are OPTIONAL - only include them if explicitly requested in the feature specification.
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
## Format: `[ID] [P?] [Story] Description`
- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions
## Path Conventions
- **Single project**: `src/`, `tests/` at repository root
- **Web app**: `backend/src/`, `frontend/src/`
- **Mobile**: `api/src/`, `ios/src/` or `android/src/`
- Paths shown below assume single project - adjust based on plan.md structure
<!--
============================================================================
IMPORTANT: The tasks below are SAMPLE TASKS for illustration purposes only.
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
- Endpoints from contracts/
Tasks MUST be organized by user story so each story can be:
- Implemented independently
- Tested independently
- Delivered as an MVP increment
DO NOT keep these sample tasks in the generated tasks.md file.
============================================================================
-->
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Project initialization and basic structure
- [ ] T001 Create project structure per implementation plan
- [ ] T002 Initialize [language] project with [framework] dependencies
- [ ] T003 [P] Configure linting and formatting tools
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
Examples of foundational tasks (adjust based on your project):
- [ ] T004 Setup database schema and migrations framework
- [ ] T005 [P] Implement authentication/authorization framework
- [ ] T006 [P] Setup API routing and middleware structure
- [ ] T007 Create base models/entities that all stories depend on
- [ ] T008 Configure error handling and logging infrastructure
- [ ] T009 Setup environment configuration management
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
---
## Phase 3: User Story 1 - [Title] (Priority: P1) 🎯 MVP
**Goal**: [Brief description of what this story delivers]
**Independent Test**: [How to verify this story works on its own]
### Tests for User Story 1 (OPTIONAL - only if tests requested) ⚠️
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
- [ ] T010 [P] [US1] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T011 [P] [US1] Integration test for [user journey] in tests/integration/test_[name].py
### Implementation for User Story 1
- [ ] T012 [P] [US1] Create [Entity1] model in src/models/[entity1].py
- [ ] T013 [P] [US1] Create [Entity2] model in src/models/[entity2].py
- [ ] T014 [US1] Implement [Service] in src/services/[service].py (depends on T012, T013)
- [ ] T015 [US1] Implement [endpoint/feature] in src/[location]/[file].py
- [ ] T016 [US1] Add validation and error handling
- [ ] T017 [US1] Add logging for user story 1 operations
**Checkpoint**: At this point, User Story 1 should be fully functional and testable independently
---
## Phase 4: User Story 2 - [Title] (Priority: P2)
**Goal**: [Brief description of what this story delivers]
**Independent Test**: [How to verify this story works on its own]
### Tests for User Story 2 (OPTIONAL - only if tests requested) ⚠️
- [ ] T018 [P] [US2] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T019 [P] [US2] Integration test for [user journey] in tests/integration/test_[name].py
### Implementation for User Story 2
- [ ] T020 [P] [US2] Create [Entity] model in src/models/[entity].py
- [ ] T021 [US2] Implement [Service] in src/services/[service].py
- [ ] T022 [US2] Implement [endpoint/feature] in src/[location]/[file].py
- [ ] T023 [US2] Integrate with User Story 1 components (if needed)
**Checkpoint**: At this point, User Stories 1 AND 2 should both work independently
---
## Phase 5: User Story 3 - [Title] (Priority: P3)
**Goal**: [Brief description of what this story delivers]
**Independent Test**: [How to verify this story works on its own]
### Tests for User Story 3 (OPTIONAL - only if tests requested) ⚠️
- [ ] T024 [P] [US3] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T025 [P] [US3] Integration test for [user journey] in tests/integration/test_[name].py
### Implementation for User Story 3
- [ ] T026 [P] [US3] Create [Entity] model in src/models/[entity].py
- [ ] T027 [US3] Implement [Service] in src/services/[service].py
- [ ] T028 [US3] Implement [endpoint/feature] in src/[location]/[file].py
**Checkpoint**: All user stories should now be independently functional
---
[Add more user story phases as needed, following the same pattern]
---
## Phase N: Polish & Cross-Cutting Concerns
**Purpose**: Improvements that affect multiple user stories
- [ ] TXXX [P] Documentation updates in docs/
- [ ] TXXX Code cleanup and refactoring
- [ ] TXXX Performance optimization across all stories
- [ ] TXXX [P] Additional unit tests (if requested) in tests/unit/
- [ ] TXXX Security hardening
- [ ] TXXX Run quickstart.md validation
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: No dependencies - can start immediately
- **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
- **User Stories (Phase 3+)**: All depend on Foundational phase completion
- User stories can then proceed in parallel (if staffed)
- Or sequentially in priority order (P1 → P2 → P3)
- **Polish (Final Phase)**: Depends on all desired user stories being complete
### User Story Dependencies
- **User Story 1 (P1)**: Can start after Foundational (Phase 2) - No dependencies on other stories
- **User Story 2 (P2)**: Can start after Foundational (Phase 2) - May integrate with US1 but should be independently testable
- **User Story 3 (P3)**: Can start after Foundational (Phase 2) - May integrate with US1/US2 but should be independently testable
### Within Each User Story
- Tests (if included) MUST be written and FAIL before implementation
- Models before services
- Services before endpoints
- Core implementation before integration
- Story complete before moving to next priority
### Parallel Opportunities
- All Setup tasks marked [P] can run in parallel
- All Foundational tasks marked [P] can run in parallel (within Phase 2)
- Once Foundational phase completes, all user stories can start in parallel (if team capacity allows)
- All tests for a user story marked [P] can run in parallel
- Models within a story marked [P] can run in parallel
- Different user stories can be worked on in parallel by different team members
---
## Parallel Example: User Story 1
```bash
# Launch all tests for User Story 1 together (if tests requested):
Task: "Contract test for [endpoint] in tests/contract/test_[name].py"
Task: "Integration test for [user journey] in tests/integration/test_[name].py"
# Launch all models for User Story 1 together:
Task: "Create [Entity1] model in src/models/[entity1].py"
Task: "Create [Entity2] model in src/models/[entity2].py"
```
---
## Implementation Strategy
### MVP First (User Story 1 Only)
1. Complete Phase 1: Setup
2. Complete Phase 2: Foundational (CRITICAL - blocks all stories)
3. Complete Phase 3: User Story 1
4. **STOP and VALIDATE**: Test User Story 1 independently
5. Deploy/demo if ready
### Incremental Delivery
1. Complete Setup + Foundational → Foundation ready
2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
3. Add User Story 2 → Test independently → Deploy/Demo
4. Add User Story 3 → Test independently → Deploy/Demo
5. Each story adds value without breaking previous stories
### Parallel Team Strategy
With multiple developers:
1. Team completes Setup + Foundational together
2. Once Foundational is done:
- Developer A: User Story 1
- Developer B: User Story 2
- Developer C: User Story 3
3. Stories complete and integrate independently
---
## Notes
- [P] tasks = different files, no dependencies
- [Story] label maps task to specific user story for traceability
- Each user story should be independently completable and testable
- Verify tests fail before implementing
- Commit after each task or logical group
- Stop at any checkpoint to validate story independently
- Avoid: vague tasks, same file conflicts, cross-story dependencies that break independence

View File

@@ -1,7 +1,5 @@
description = "Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts."
prompt = """
---
name: speckit.taskstoissues
description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts.
tools: ['github/github-mcp-server/issue_write']
---
@@ -14,9 +12,15 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Outline
## Role
1. Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. 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").
You are the **Antigravity Tracker Integrator**. Your role is to synchronize technical tasks with external project management systems like GitHub Issues. You ensure that every piece of work has a clear, tracked identity for collaborative execution.
## Task
### Outline
1. Run `../scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. 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").
1. From the executed script, extract the path to **tasks**.
1. Get the Git remote by running:
@@ -29,4 +33,3 @@ git config --get remote.origin.url
1. For each task in the list, use the GitHub MCP server to create a new issue in the repository that is representative of the Git remote.
**UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL**
"""

View File

@@ -0,0 +1,119 @@
---
name: speckit.tester
description: Execute tests, measure coverage, and report results.
version: 1.0.0
depends-on: []
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Test Runner**. Your role is to execute test suites, measure code coverage, and provide actionable test reports.
## Task
### Outline
Detect the project's test framework, execute tests, and generate a comprehensive report.
### Execution Steps
1. **Detect Test Framework**:
```bash
# Check package.json for test frameworks
cat package.json 2>/dev/null | grep -E "(jest|vitest|mocha|ava|tap)"
# Check for Python test frameworks
ls pytest.ini setup.cfg pyproject.toml 2>/dev/null
# Check for Go tests
find . -name "*_test.go" -maxdepth 3 2>/dev/null | head -1
```
| Indicator | Framework |
|-----------|-----------|
| `jest` in package.json | Jest |
| `vitest` in package.json | Vitest |
| `pytest.ini` or `[tool.pytest]` | Pytest |
| `*_test.go` files | Go test |
| `Cargo.toml` + `#[test]` | Cargo test |
2. **Run Tests with Coverage**:
| Framework | Command |
|-----------|---------|
| Jest | `npx jest --coverage --json --outputFile=coverage/test-results.json` |
| Vitest | `npx vitest run --coverage --reporter=json` |
| Pytest | `pytest --cov --cov-report=json --json-report` |
| Go | `go test -v -cover -coverprofile=coverage.out ./...` |
| Cargo | `cargo test -- --test-threads=1` |
3. **Parse Test Results**:
Extract from test output:
- Total tests
- Passed / Failed / Skipped
- Execution time
- Coverage percentage (if available)
4. **Identify Failures**:
For each failing test:
- Test name and file location
- Error message
- Stack trace (truncated to relevant lines)
- Suggested fix (if pattern is recognizable)
5. **Generate Report**:
```markdown
# Test Report
**Date**: [timestamp]
**Framework**: [detected]
**Status**: PASS | FAIL
## Summary
| Metric | Value |
|--------|-------|
| Total Tests | X |
| Passed | X |
| Failed | X |
| Skipped | X |
| Duration | X.Xs |
| Coverage | X% |
## Failed Tests
### [test name]
**File**: `path/to/test.ts:42`
**Error**: Expected X but received Y
**Suggestion**: Check mock setup for...
## Coverage by File
| File | Lines | Branches | Functions |
|------|-------|----------|-----------|
| src/auth.ts | 85% | 70% | 90% |
## Next Actions
1. Fix failing test: [name]
2. Increase coverage in: [low coverage files]
```
6. **Output**:
- Display report in terminal
- Optionally save to `FEATURE_DIR/test-report.md`
## Operating Principles
- **Run All Tests**: Don't skip tests unless explicitly requested
- **Preserve Output**: Keep full test output for debugging
- **Be Helpful**: Suggest fixes for common failure patterns
- **Respect Timeouts**: Set reasonable timeout (5 min default)

View File

@@ -0,0 +1,93 @@
---
name: speckit.validate
description: Validate that implementation matches specification requirements.
version: 1.0.0
depends-on:
- speckit.implement
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Role
You are the **Antigravity Validator**. Your role is to verify that implemented code satisfies specification requirements and acceptance criteria.
## Task
### Outline
Post-implementation validation that compares code against spec requirements.
### Execution Steps
1. **Setup**:
- Run `../scripts/bash/check-prerequisites.sh --json --require-tasks`
- Parse FEATURE_DIR from output
- Load: `spec.md`, `plan.md`, `tasks.md`
2. **Build Requirements Matrix**:
Extract from spec.md:
- All functional requirements
- All acceptance criteria
- All success criteria
- Edge cases listed
3. **Scan Implementation**:
From tasks.md, identify all files created/modified:
- Read each file
- Extract functions, classes, endpoints
- Map to requirements (by name matching, comments, or explicit references)
4. **Validation Checks**:
| Check | Method |
|-------|--------|
| Requirement Coverage | Each requirement has ≥1 implementation reference |
| Acceptance Criteria | Each criterion is testable in code |
| Edge Case Handling | Each edge case has explicit handling code |
| Test Coverage | Each requirement has ≥1 test |
5. **Generate Validation Report**:
```markdown
# Validation Report: [Feature Name]
**Date**: [timestamp]
**Status**: PASS | PARTIAL | FAIL
## Coverage Summary
| Metric | Count | Percentage |
|--------|-------|------------|
| Requirements Covered | X/Y | Z% |
| Acceptance Criteria Met | X/Y | Z% |
| Edge Cases Handled | X/Y | Z% |
| Tests Present | X/Y | Z% |
## Uncovered Requirements
| Requirement | Status | Notes |
|-------------|--------|-------|
| [REQ-001] | Missing | No implementation found |
## Recommendations
1. [Action item for gaps]
```
6. **Output**:
- Display report
- Write to `FEATURE_DIR/validation-report.md`
- Set exit status based on coverage threshold (default: 80%)
## Operating Principles
- **Be Thorough**: Check every requirement, not just obvious ones
- **Be Fair**: Semantic matching, not just keyword matching
- **Be Actionable**: Every gap should have a clear fix recommendation
- **Don't Block on Style**: Focus on functional coverage, not code style

View File

@@ -0,0 +1,47 @@
---
description: Run the full speckit pipeline from specification to analysis in one command.
---
# Workflow: speckit.all
This meta-workflow orchestrates the complete specification pipeline.
## Pipeline Steps
1. **Specify** (`/speckit.specify`):
- Use the `view_file` tool to read: `.agent/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: `.agent/skills/speckit.clarify/SKILL.md`
- Execute to resolve ambiguities
- Updates: `spec.md`
3. **Plan** (`/speckit.plan`):
- Use the `view_file` tool to read: `.agent/skills/speckit.plan/SKILL.md`
- Execute to create technical design
- Creates: `plan.md`
4. **Tasks** (`/speckit.tasks`):
- Use the `view_file` tool to read: `.agent/skills/speckit.tasks/SKILL.md`
- Execute to generate task breakdown
- Creates: `tasks.md`
5. **Analyze** (`/speckit.analyze`):
- Use the `view_file` tool to read: `.agent/skills/speckit.analyze/SKILL.md`
- Execute to validate consistency
- Output: Analysis report
## Usage
```
/speckit.all "Build a user authentication system with OAuth2 support"
```
## On Error
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")

View File

@@ -0,0 +1,18 @@
---
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
---
# 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: `.agent/skills/speckit.constitution/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 `.specify/` directory doesn't exist: Initialize the speckit structure first

View File

@@ -0,0 +1,19 @@
---
description: Create or update the feature specification from a natural language feature description.
---
# 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: `.agent/skills/speckit.specify/SKILL.md`
3. **Execute**:
- Follow the instructions in the `SKILL.md` exactly.
- Apply the user's prompt as the feature description for the skill's logic.
4. **On Error**:
- If no feature description provided: Ask the user to describe the feature they want to specify

View File

@@ -0,0 +1,18 @@
---
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
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: `.agent/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

View File

@@ -0,0 +1,18 @@
---
description: Execute the implementation planning workflow using the plan template to generate design artifacts.
---
# 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: `.agent/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

View File

@@ -0,0 +1,19 @@
---
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
---
# 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: `.agent/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

View File

@@ -0,0 +1,22 @@
---
description: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation.
---
// turbo-all
# 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: `.agent/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

View File

@@ -0,0 +1,20 @@
---
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md
---
# 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: `.agent/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

View File

@@ -0,0 +1,21 @@
---
description: Run static analysis tools and aggregate results.
---
// turbo-all
# 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: `.agent/skills/speckit.checker/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 linting tools available: Report which tools to install based on project type
- If tools fail: Show raw error and suggest config fixes

View File

@@ -0,0 +1,21 @@
---
description: Execute tests, measure coverage, and report results.
---
// turbo-all
# 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: `.agent/skills/speckit.tester/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 test framework detected: Report "No test framework found. Install Jest, Vitest, Pytest, or similar."
- If tests fail: Show failure details and suggest fixes

View File

@@ -0,0 +1,19 @@
---
description: Perform code review with actionable feedback and suggestions.
---
# 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: `.agent/skills/speckit.reviewer/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 files to review: Ask user to stage changes or specify file paths
- If not a git repo: Review current directory files instead

View File

@@ -0,0 +1,19 @@
---
description: Validate that implementation matches specification requirements.
---
# 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: `.agent/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

View File

@@ -0,0 +1,49 @@
---
description: Create a new NestJS backend feature module following project standards
---
# Create NestJS Backend Module
Use this workflow when creating a new feature module in `backend/src/modules/`.
Follows `specs/05-Engineering-Guidelines/05-02-backend-guidelines.md` and ADR-005.
## Steps
1. **Verify requirements exist** — confirm the feature is in `specs/01-Requirements/` before starting
2. **Check schema** — read `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql` for relevant tables
3. **Scaffold module folder**
```
backend/src/modules/<module-name>/
├── <module-name>.module.ts
├── <module-name>.controller.ts
├── <module-name>.service.ts
├── dto/
│ ├── create-<module-name>.dto.ts
│ └── update-<module-name>.dto.ts
├── entities/
│ └── <module-name>.entity.ts
└── <module-name>.controller.spec.ts
```
4. **Create Entity** — map ONLY columns defined in the schema SQL. Use TypeORM decorators. Add `@VersionColumn()` if the entity needs optimistic locking.
5. **Create DTOs** — use `class-validator` decorators. Never use `any`. Validate all inputs.
6. **Create Service** — inject repository via constructor DI. Use transactions for multi-step writes. Add `Idempotency-Key` guard for POST/PUT/PATCH operations.
7. **Create Controller** — apply `@UseGuards(JwtAuthGuard, CaslAbilityGuard)`. Use proper HTTP status codes. Document with `@ApiTags` and `@ApiOperation`.
8. **Register in Module** — add to `imports`, `providers`, `controllers`, `exports` as needed.
9. **Register in AppModule** — import the new module in `app.module.ts`.
10. **Write unit test** — cover service methods with Jest mocks. Run:
```bash
pnpm test:watch
```
11. **Citation** — confirm implementation references `specs/01-Requirements/` and `specs/05-Engineering-Guidelines/05-02-backend-guidelines.md`

View File

@@ -0,0 +1,64 @@
---
description: Create a new Next.js App Router page following project standards
---
# Create Next.js Frontend Page
Use this workflow when creating a new page in `frontend/app/`.
Follows `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md`, ADR-011, ADR-012, ADR-013, ADR-014.
## Steps
1. **Determine route** — decide the route path, e.g. `app/(dashboard)/documents/page.tsx`
2. **Classify components** — decide what is Server Component (default) vs Client Component (`'use client'`)
- Server Component: initial data load, static content, SEO
- Client Component: interactivity, forms, TanStack Query hooks, Zustand
3. **Create page file** — Server Component by default:
```typescript
// app/(dashboard)/<route>/page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: '<Page Title> | LCBP3-DMS',
};
export default async function <PageName>Page() {
return (
<div>
{/* Page content */}
</div>
);
}
```
4. **Create API hook** (if client-side data needed) — add to `hooks/use-<feature>.ts`:
```typescript
'use client';
import { useQuery } from '@tanstack/react-query';
import { apiClient } from '@/lib/api-client';
export function use<Feature>() {
return useQuery({
queryKey: ['<feature>'],
queryFn: () => apiClient.get('<endpoint>'),
});
}
```
5. **Build UI components** — use Shadcn/UI primitives. Place reusable components in `components/<feature>/`.
6. **Handle forms** — use React Hook Form + Zod schema validation. Never access form values without validation.
7. **Handle errors** — add `error.tsx` alongside `page.tsx` for route-level error boundaries.
8. **Add loading state** — add `loading.tsx` for Suspense fallback if page does async work.
9. **Add to navigation** — update sidebar/nav config if the page should appear in the menu.
10. **Access control** — ensure page checks CASL permissions. Redirect unauthorized users via middleware or `notFound()`.
11. **Citation** — confirm implementation references `specs/01-Requirements/` and `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md`

View File

@@ -0,0 +1,71 @@
---
description: Deploy the application via Gitea Actions to QNAP Container Station
---
# Deploy to Production
Use this workflow to deploy updated backend and/or frontend to QNAP via Gitea Actions CI/CD.
Follows `specs/04-Infrastructure-OPS/` and ADR-015.
## Pre-deployment Checklist
- [ ] All tests pass locally (`pnpm test:watch`)
- [ ] No TypeScript errors (`tsc --noEmit`)
- [ ] No `any` types introduced
- [ ] Schema changes applied to `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`
- [ ] Environment variables documented (NOT in `.env` files)
## Steps
1. **Commit and push to Gitea**
```bash
git status
git add .
git commit -m "feat(<scope>): <description>"
git push origin main
```
2. **Monitor Gitea Actions** — open Gitea web UI → Actions tab → verify pipeline starts
3. **Pipeline stages (automatic)**
- `build-backend` → Docker image build + push to registry
- `build-frontend` → Docker image build + push to registry
- `deploy` → SSH to QNAP → `docker compose pull` + `docker compose up -d`
4. **Verify backend health**
```bash
curl http://<QNAP_IP>:3000/health
# Expected: { "status": "ok" }
```
5. **Verify frontend**
```bash
curl -I http://<QNAP_IP>:3001
# Expected: HTTP 200
```
6. **Check logs in Grafana** — navigate to Grafana → Loki → filter by container name
- Backend: `container_name="lcbp3-backend"`
- Frontend: `container_name="lcbp3-frontend"`
7. **Verify database** — confirm schema changes are reflected (if any)
8. **Rollback (if needed)**
```bash
# SSH into QNAP
docker compose pull <service>=<previous-image-tag>
docker compose up -d <service>
```
## Common Issues
| Symptom | Cause | Fix |
| ----------------- | --------------------- | ----------------------------------- |
| Backend unhealthy | DB connection failed | Check MariaDB container + env vars |
| Frontend blank | Build error | Check Next.js build logs in Grafana |
| 502 Bad Gateway | Container not started | `docker compose ps` to check status |
| Pipeline stuck | Gitea runner offline | Restart runner on QNAP |

View File

@@ -0,0 +1,27 @@
---
description: Execute the full preparation pipeline (Specify -> Clarify -> Plan -> Tasks -> Analyze) in sequence.
---
# 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 `.agent/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 `.agent/skills/speckit.clarify/SKILL.md`.
3. **Step 3: Plan (Skill 04)**
- Goal: Generate `plan.md` from the finalized spec.
- Action: Read and execute `.agent/skills/speckit.plan/SKILL.md`.
4. **Step 4: Tasks (Skill 05)**
- Goal: Generate actional `tasks.md` from the plan.
- Action: Read and execute `.agent/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 `.agent/skills/speckit.analyze/SKILL.md`.

View File

@@ -0,0 +1,18 @@
---
description: Generate a custom checklist for the current feature based on user requirements.
---
# 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: `.agent/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

View File

@@ -0,0 +1,19 @@
---
description: Compare two versions of a spec or plan to highlight changes.
---
# 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: `.agent/skills/speckit.diff/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 files to compare: Use current feature's `spec.md` vs git HEAD
- If `spec.md` doesn't exist: Run `/speckit.specify` first

View File

@@ -0,0 +1,19 @@
---
description: Migrate existing projects into the speckit structure by generating spec.md, plan.md, and tasks.md from existing code.
---
# 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: `.agent/skills/speckit.migrate/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 path doesn't exist: Ask user to provide valid directory path
- If no code found: Report that no analyzable code was detected

View File

@@ -0,0 +1,20 @@
---
description: Challenge the specification with Socratic questioning to identify logical gaps, unhandled edge cases, and robustness issues.
---
// turbo-all
# 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: `.agent/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`).

View File

@@ -0,0 +1,20 @@
---
description: Display a dashboard showing feature status, completion percentage, and blockers.
---
// turbo-all
# 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: `.agent/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."

View File

@@ -0,0 +1,18 @@
---
description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts.
---
# 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: `.agent/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

View File

@@ -7,35 +7,67 @@ trigger: always_on
## 🧠 Role & Persona
Act as a **Senior Full Stack Developer** expert in **NestJS**, **Next.js**, and **TypeScript**.
You are a **Document Intelligence Engine** — not a general chatbot.
You value **Data Integrity**, **Security**, and **Clean Architecture**.
## 🏗️ Project Overview
This is **LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)**.
**LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)** — Version 1.8.0
- **Goal:** Manage construction documents (Correspondence, RFA, Drawings) with complex approval workflows.
- **Infrastructure:** Deployed on QNAP Server via Docker Container Station.
- **Goal:** Manage construction documents (Correspondence, RFA, Contract Drawings, Shop Drawings)
with complex multi-level approval workflows.
- **Infrastructure:** QNAP Container Station (Docker Compose), Nginx Proxy Manager (Reverse Proxy),
Gitea (Git + CI/CD), n8n (Workflow Automation), Prometheus + Loki + Grafana (Monitoring/Logging)
## 💻 Tech Stack & Constraints
- **Backend:** NestJS (Modular Architecture), TypeORM, MariaDB 11.8, Redis 7.2 (BullMQ), Elasticsearch 8.11, JWT (JSON Web Tokens), CASL (4-Level RBAC).
- **Frontend:** Next.js 14+ (App Router), Tailwind CSS, Shadcn/UI, TanStack Query (Server State), Zustand (Client State), React Hook Form + Zod, Axios.
- **Backend:** NestJS (Modular Architecture), TypeORM, MariaDB 11.8, Redis 7.2 (BullMQ),
Elasticsearch 8.11, JWT + Passport, CASL (4-Level RBAC), ClamAV (Virus Scanning), Helmet.js
- **Frontend:** Next.js 14+ (App Router), Tailwind CSS, Shadcn/UI,
TanStack Query (**Server State**), Zustand (**Client State**), React Hook Form + Zod (**Form State**), Axios
- **Notifications:** BullMQ Queue → Email / LINE Notify / In-App
- **Language:** TypeScript (Strict Mode). **NO `any` types allowed.**
## 🛡️ Security & Integrity Rules
1. **Idempotency:** All critical POST/PUT requests MUST check for `Idempotency-Key` header.
2. **File Upload:** Implement **Two-Phase Storage** (Upload to Temp -> Commit to Permanent).
3. **Race Conditions:** Use **Redis Lock** + **Optimistic Locking** for Document Numbering generation.
4. **Validation:** Use Zod or Class-validator for all inputs.
1. **Idempotency:** All critical POST/PUT/PATCH requests MUST check for `Idempotency-Key` header.
2. **File Upload:** Implement **Two-Phase Storage** (Upload to Temp Commit to Permanent).
3. **Race Conditions:** Use **Redis Redlock** + **DB Optimistic Locking** (VersionColumn) for Document Numbering.
4. **Validation:** Use Zod (frontend) or Class-validator (backend DTO) for all inputs.
5. **Password:** bcrypt with 12 salt rounds. Enforce password policy.
6. **Rate Limiting:** Apply ThrottlerGuard on auth endpoints.
## workflow Guidelines
## 📋 Workflow & Spec Guidelines
- When implementing strictly follow the documents in `specs/`.
- Always verify database schema against `specs/07-database/` before writing queries.
- Always follow specs in `specs/` (v1.8.0). Priority: `06-Decision-Records` > `05-Engineering-Guidelines` > others.
- Always verify database schema against **`specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`** before writing queries.
- Adhere to ADRs: ADR-001 (Workflow Engine), ADR-002 (Doc Numbering), ADR-009 (DB Strategy),
ADR-011 (App Router), ADR-013 (Form Handling), ADR-016 (Security).
## 🎯 Active Skills
- **`nestjs-best-practices`** — Apply when writing/reviewing any NestJS code (modules, services, controllers, guards, interceptors, DTOs)
- **`next-best-practices`** — Apply when writing/reviewing any Next.js code (App Router, RSC boundaries, async patterns, data fetching, error handling)
## 🔄 Speckit Workflow Pipeline
Use `/slash-command` to trigger these workflows. Always prefer spec-driven development for new features.
| Phase | Command | เมื่อใช้ |
| -------------------- | ---------------------------------------------------------- | --------------------------------------------------- |
| **Feature Design** | `/speckit.prepare` | Feature ใหม่ — รัน Specify→Clarify→Plan→Tasks→Analyze |
| **Implement** | `/07-speckit.implement` | เขียนโค้ดตาม tasks.md พร้อม anti-regression |
| **QA** | `/08-speckit.checker` | ตรวจ TypeScript + ESLint + Security |
| **Test** | `/09-speckit.tester` | รัน Jest/Vitest + coverage report |
| **Review** | `/10-speckit.reviewer` | Code review — Logic, Performance, Style |
| **Validate** | `/11-speckit.validate` | ยืนยันว่า implementation ตรงกับ spec.md |
| **Project-Specific** | `/create-backend-module` `/create-frontend-page` `/deploy` | งานประจำของ LCBP3-DMS |
## 🚫 Forbidden Actions
- DO NOT use SQL Triggers (Business logic must be in NestJS services).
- DO NOT use `.env` files for production configuration (Use Docker environment variables).
- DO NOT run database migrations — modify the schema SQL file directly.
- DO NOT invent table names or columns — use ONLY what is defined in the schema SQL file.
- DO NOT generate code that violates OWASP Top 10 security practices.
- DO NOT use `any` TypeScript type anywhere.

View File

@@ -1,139 +0,0 @@
description = "Execute the implementation plan by processing and executing all tasks defined in tasks.md"
prompt = """
---
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
1. Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. 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. **Check checklists status** (if FEATURE_DIR/checklists/ exists):
- Scan all checklist files in the checklists/ directory
- For each checklist, count:
- Total items: All lines matching `- [ ]` or `- [X]` or `- [x]`
- Completed items: Lines matching `- [X]` or `- [x]`
- Incomplete items: Lines matching `- [ ]`
- Create a status table:
```text
| Checklist | Total | Completed | Incomplete | Status |
|-----------|-------|-----------|------------|--------|
| ux.md | 12 | 12 | 0 | PASS |
| test.md | 8 | 5 | 3 | FAIL |
| security.md | 6 | 6 | 0 | PASS |
```
- Calculate overall status:
- **PASS**: All checklists have 0 incomplete items
- **FAIL**: One or more checklists have incomplete items
- **If any checklist is incomplete**:
- Display the table with incomplete item counts
- **STOP** and ask: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
- Wait for user response before continuing
- If user says "no" or "wait" or "stop", halt execution
- If user says "yes" or "proceed" or "continue", proceed to step 3
- **If all checklists are complete**:
- Display the table showing all checklists passed
- Automatically proceed to step 3
3. Load and analyze the implementation context:
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
- **REQUIRED**: Read plan.md for tech stack, architecture, and file structure
- **IF EXISTS**: Read data-model.md for entities and relationships
- **IF EXISTS**: Read contracts/ for API specifications and test requirements
- **IF EXISTS**: Read research.md for technical decisions and constraints
- **IF EXISTS**: Read quickstart.md for integration scenarios
4. **Project Setup Verification**:
- **REQUIRED**: Create/verify ignore files based on actual project setup:
**Detection & Creation Logic**:
- Check if the following command succeeds to determine if the repository is a git repo (create/verify .gitignore if so):
```sh
git rev-parse --git-dir 2>/dev/null
```
- Check if Dockerfile* exists or Docker in plan.md create/verify .dockerignore
- Check if .eslintrc* exists create/verify .eslintignore
- Check if eslint.config.* exists ensure the config's `ignores` entries cover required patterns
- Check if .prettierrc* exists create/verify .prettierignore
- Check if .npmrc or package.json exists create/verify .npmignore (if publishing)
- Check if terraform files (*.tf) exist create/verify .terraformignore
- Check if .helmignore needed (helm charts present) create/verify .helmignore
**If ignore file already exists**: Verify it contains essential patterns, append missing critical patterns only
**If ignore file missing**: Create with full pattern set for detected technology
**Common Patterns by Technology** (from plan.md tech stack):
- **Node.js/JavaScript/TypeScript**: `node_modules/`, `dist/`, `build/`, `*.log`, `.env*`
- **Python**: `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `dist/`, `*.egg-info/`
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
**Tool-Specific Patterns**:
- **Docker**: `node_modules/`, `.git/`, `Dockerfile*`, `.dockerignore`, `*.log*`, `.env*`, `coverage/`
- **ESLint**: `node_modules/`, `dist/`, `build/`, `coverage/`, `*.min.js`
- **Prettier**: `node_modules/`, `dist/`, `build/`, `coverage/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
- **Terraform**: `.terraform/`, `*.tfstate*`, `*.tfvars`, `.terraform.lock.hcl`
- **Kubernetes/k8s**: `*.secret.yaml`, `secrets/`, `.kube/`, `kubeconfig*`, `*.key`, `*.crt`
5. Parse tasks.md structure and extract:
- **Task phases**: Setup, Tests, Core, Integration, Polish
- **Task dependencies**: Sequential vs parallel execution rules
- **Task details**: ID, description, file paths, parallel markers [P]
- **Execution flow**: Order and dependency requirements
6. Execute implementation following the task plan:
- **Phase-by-phase execution**: Complete each phase before moving to the next
- **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
- **File-based coordination**: Tasks affecting the same files must run sequentially
- **Validation checkpoints**: Verify each phase completion before proceeding
7. Implementation execution rules:
- **Setup first**: Initialize project structure, dependencies, configuration
- **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
- **Core development**: Implement models, services, CLI commands, endpoints
- **Integration work**: Database connections, middleware, logging, external services
- **Polish and validation**: Unit tests, performance optimization, documentation
8. Progress tracking and error handling:
- Report progress after each completed task
- Halt execution if any non-parallel task fails
- For parallel tasks [P], continue with successful tasks, report failed ones
- Provide clear error messages with context for debugging
- Suggest next steps if implementation cannot proceed
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
9. Completion validation:
- Verify all required tasks are completed
- Check that implemented features match the original specification
- Validate that tests pass and coverage meets requirements
- Confirm the implementation follows the technical plan
- Report final status with summary of completed work
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.
"""

View File

@@ -3,18 +3,40 @@
## [Unreleased]
### In Progress
- Backend Document Numbering Refactor (TASK-BE-017)
- E2E Testing & UAT preparation
- Production deployment preparation
- Continuous Integration & End-to-End Test (E2E) Improvements
- Advanced Analytics Dashboard Planning
## 1.8.0 (2026-02-24)
### Summary
**Documentation Realignment & Type Safety** - Comprehensive overhaul of the specifications structure and frontend codebase to enforce strict typing and consistency.
### Codebase Changes 💻
- **Frontend Type Safety**: Removed all `any` types from Frontend DTOs and Hooks. Implemented explicit types (`AuditLog[]`, `Record<string, unknown>`) avoiding implicit fallbacks.
- **Frontend Refactoring**: Refactored data fetching and mutations utilizing `TanStack Query` hooks aligned with real API endpoints.
- **Admin Pages Fixes**: Addressed crashes on Reference Data/Categories pages by introducing robust error handling and proper generic typing on DataTables.
### Documentation 📚
- **Specification Restructuring**: Restructured the entire `specs/` directory into 7 canonical layers (`00-Overview`, `01-Requirements`, `02-Architecture`, `03-Data-and-Storage`, `04-Infrastructure-OPS`, `05-Engineering-Guidelines`, `06-Decision-Records`).
- **Guidelines Synchronization**: Updated Engineering Guidelines (`05-1` to `05-4`) to reflect the latest state management (Zustand, React Hook Form) and testing strategies.
- **ADR Alignment**: Audited Architecture Decision Records (ADR 1 to 16) against actual implementation (e.g., LocalStorage JWT vs HTTP-Only cookies, bcrypt salt rounds).
- **Root Docs Update**: Fully updated `README.md` and `CONTRIBUTING.md` to reflect the current v1.8.0 folder structure and rules.
- **Cleanups**: Consolidated standalone infrastructure specs (formerly `08-infrastructure`) into `04-Infrastructure-OPS` and cleaned up legacy scripts and blank diagrams from the repository root.
## 1.7.0 (2025-12-18)
### Summary
**Schema Stabilization & Document Numbering Overhaul** - Significant schema updates to support advanced document numbering (reservations, varying reset scopes) and a unified workflow engine.
### Database Schema Changes 💾
#### Document Numbering System (V2) 🔢
- **`document_number_counters`**:
- **Breaking Change**: Primary Key changed to 8-column Composite Key (`project_id`, `originator_id`, `recipient_id`, `type_id`, `sub_type_id`, `rfa_type_id`, `discipline_id`, `reset_scope`).
- **New Feature**: Added `reset_scope` column to support flexible resetting (YEAR, MONTH, PROJECT, NONE).
@@ -28,6 +50,7 @@
- Enhanced with reservation tokens and performance metrics.
#### Unified Workflow Engine 🔄
- **`workflow_definitions`**:
- Updated structure to support compiled DSL and versioning.
- Added `dsl` (JSON) and `compiled` (JSON) columns.
@@ -38,6 +61,7 @@
- Updated to link with UUID instances.
#### System & Audit 🛡️
- **`audit_logs`**:
- Updated schema for better partitioning support (`created_at` in PK).
- Standardized JSON details column.
@@ -45,25 +69,30 @@
- Updated schema to support polymorphic entity linking.
#### Master Data
- **`disciplines`**:
- Added relation to `correspondences` and `rfas`.
### Documentation 📚
- **Data Dictionary**: Updated to v1.7.0 with full index summaries and business rules.
- **Schema**: Released `lcbp3-v1.7.0-schema.sql` and `lcbp3-v1.7.0-seed.sql`.
## 1.6.0 (2025-12-13)
### Summary
**Schema Refactoring Release** - Major restructuring of correspondence and RFA tables for improved data consistency.
### Database Schema Changes 💾
#### Breaking Changes ⚠️
- **`correspondence_recipients`**: FK changed from `correspondence_revisions(correspondence_id)``correspondences(id)`
- **`rfa_items`**: Column renamed `rfarev_correspondence_id``rfa_revision_id`
#### Schema Refactoring
- **`correspondences`**: Reordered columns, `discipline_id` now inline (no ALTER TABLE)
- **`correspondence_revisions`**:
- Renamed: `title``subject`
@@ -79,12 +108,14 @@
- Added Virtual Column: `v_ref_drawing_count`
### Documentation 📚
- Updated Data Dictionary to v1.6.0
- Updated schema SQL files (`lcbp3-v1.6.0-schema.sql`, seed files)
## 1.5.1 (2025-12-10)
### Summary
**Major Milestone: System Feature Complete (~95%)** - Ready for UAT and production deployment.
All core modules implemented and operational. Backend and frontend fully integrated with comprehensive admin tools.
@@ -92,6 +123,7 @@ All core modules implemented and operational. Backend and frontend fully integra
### Backend Completed ✅
#### Core Infrastructure
- ✅ All 18 core modules implemented and tested
- ✅ JWT Authentication with Refresh Token mechanism
- ✅ RBAC 4-Level (Global, Organization, Project, Contract) using CASL
@@ -102,6 +134,7 @@ All core modules implemented and operational. Backend and frontend fully integra
- ✅ Health Monitoring & Metrics endpoints
#### Business Modules
-**Correspondence Module** - Master-Revision pattern, Workflow integration, References
-**RFA Module** - Full CRUD, Item management, Revision handling, Approval workflow
-**Drawing Module** - Separated into Shop Drawing & Contract Drawing
@@ -110,6 +143,7 @@ All core modules implemented and operational. Backend and frontend fully integra
-**Elasticsearch Integration** - Direct indexing, Full-text search (95% complete)
#### Supporting Services
-**Notification System** - Email and LINE notification integration
-**Master Data Management** - Consolidated service for Organizations, Projects, Disciplines, Types
-**User Management** - CRUD, Assignments, Preferences, Soft Delete
@@ -119,6 +153,7 @@ All core modules implemented and operational. Backend and frontend fully integra
### Frontend Completed ✅
#### Application Structure
- ✅ All 15 frontend tasks (FE-001 to FE-015) completed
- ✅ Next.js 14 App Router with TypeScript
- ✅ Complete UI implementation (17 component groups, 22 Shadcn/UI components)
@@ -128,6 +163,7 @@ All core modules implemented and operational. Backend and frontend fully integra
- ✅ Responsive layout (Desktop & Mobile)
#### End-User Modules
-**Authentication UI** - Login, Token Management, Session Sync
-**RBAC UI** - `<Can />` component for permission-based rendering
-**Correspondence UI** - List, Create, Detail views with file uploads
@@ -139,6 +175,7 @@ All core modules implemented and operational. Backend and frontend fully integra
-**Transmittal UI** - Transmittal tracking and management
#### Admin Panel (10 Routes)
-**Workflow Configuration** - DSL Editor, Visual Builder, Workflow Definition management
-**Document Numbering Config** - Template Editor, Token Tester, Sequence Viewer
-**User Management** - CRUD, Role assignments, Preferences
@@ -151,12 +188,14 @@ All core modules implemented and operational. Backend and frontend fully integra
-**Settings** - System configuration
### Database 💾
- ✅ Schema v1.5.1 with standardized audit columns (`created_at`, `updated_at`, `deleted_at`)
- ✅ Complete seed data for all master tables
- ✅ Migration scripts and patches (`patch-audit-columns.sql`)
- ✅ Data Dictionary v1.5.1 documentation
### Documentation 📚
- ✅ Complete specs/ reorganization to v1.5.1
- ✅ 21 requirements documents in `specs/01-requirements/`
- ✅ 17 ADRs (Architecture Decision Records) in `specs/05-decisions/`
@@ -166,6 +205,7 @@ All core modules implemented and operational. Backend and frontend fully integra
- ✅ Task archiving to `specs/09-history/` (27 completed tasks)
### Bug Fixes 🐛
- 🐛 Fixed role selection bug in User Edit form (2025-12-09)
- 🐛 Fixed workflow permissions - 403 error on workflow action endpoints
- 🐛 Fixed TypeORM relation errors in RFA and Drawing services
@@ -175,6 +215,7 @@ All core modules implemented and operational. Backend and frontend fully integra
- 🐛 Fixed invalid refresh token error loop
### Changed 📝
- 📝 Updated progress reports to reflect ~95% backend, 100% frontend completion
- 📝 Aligned all TypeORM entities with schema v1.5.1
- 📝 Enhanced data dictionary with business rules
@@ -183,6 +224,7 @@ All core modules implemented and operational. Backend and frontend fully integra
## 1.5.0 (2025-11-30)
### Summary
Initial spec-kit structure establishment and documentation organization.
### Changed

View File

@@ -24,86 +24,67 @@
```
specs/
├── 00-overview/ # ภาพรวมโครงการ (3 docs)
├── 00-Overview/ # ภาพรวมโครงการ
│ ├── README.md # Project overview
│ ├── glossary.md # คำศัพท์เทคนิค
│ └── quick-start.md # Quick start guide
│ ├── 00-02-glossary.md # คำศัพท์เทคนิค
│ └── 00-01-quick-start.md # Quick start guide
├── 01-requirements/ # ข้อกำหนดระบบ (21 docs)
├── 01-Requirements/ # ข้อกำหนดระบบ (21 docs)
│ ├── README.md # Requirements overview
│ ├── 01-objectives.md # วัตถุประสงค์
│ ├── 02-architecture.md # สถาปัตยกรรม
── 03-functional-requirements.md
│ ├── 03.1-project-management.md
│ ├── 03.2-correspondence.md
│ ├── 03.3-rfa.md
│ ├── 03.4-contract-drawing.md
│ ├── 03.5-shop-drawing.md
│ ├── 03.6-unified-workflow.md
│ ├── 03.7-transmittals.md
│ ├── 03.8-circulation-sheet.md
│ ├── 03.9-logs.md
│ ├── 03.10-file-handling.md
│ ├── 03.11-document-numbering.md
│ ├── 03.12-json-details.md
│ ├── 04-access-control.md
│ ├── 05-ui-ux.md
│ ├── 06-non-functional.md
│ └── 07-testing.md
│ ├── 01-01-objectives.md # วัตถุประสงค์
│ ├── 01-02-business-rules/ # กฏธุรกิจที่ห้ามละเมิด
── 01-03-modules/ # สเปกของแต่ละฟีเจอร์หลัก
├── 02-architecture/ # สถาปัตยกรรมระบบ (4 docs)
├── 02-Architecture/ # สถาปัตยกรรมระบบ (4 docs)
│ ├── README.md
│ ├── system-architecture.md
│ ├── api-design.md
── data-model.md
│ ├── 02-01-system-context.md
│ ├── 02-02-software-architecture.md
── 02-03-network-design.md
│ └── 02-04-api-design.md
├── 03-implementation/ # แผนการพัฒนา (5 docs)
├── 03-Data-and-Storage/ # Database Schema (4 files)
│ ├── README.md
│ ├── backend-guidelines.md
│ ├── frontend-guidelines.md
── testing-strategy.md
│ └── code-standards.md
│ ├── lcbp3-v1.7.0-schema.sql
│ ├── lcbp3-v1.7.0-seed-basic.sql
── 03-01-data-dictionary.md
├── 04-operations/ # การดำเนินงาน (9 docs)
├── 04-Infrastructure-OPS/ # Deployment & Operations (9 docs)
│ ├── README.md
│ ├── deployment.md
│ ├── monitoring.md
│ ├── 04-01-docker-compose.md
│ ├── 04-03-monitoring.md
│ └── ...
├── 05-decisions/ # Architecture Decision Records (17 ADRs)
├── 05-Engineering-Guidelines/# แผนการพัฒนา (5 docs)
│ ├── README.md
│ ├── ADR-001-workflow-engine.md
│ ├── 05-01-fullstack-js-guidelines.md
│ ├── 05-02-backend-guidelines.md
│ ├── 05-03-frontend-guidelines.md
│ └── 05-04-testing-strategy.md
├── 06-Decision-Records/ # Architecture Decision Records (17 ADRs)
│ ├── README.md
│ ├── ADR-001-unified-workflow.md
│ ├── ADR-002-document-numbering.md
│ └── ...
── 06-tasks/ # Active Tasks & Progress (34 files)
├── frontend-progress-report.md
├── backend-progress-report.md
└── ...
├── 07-database/ # Database Schema (8 files)
│ ├── lcbp3-v1.7.0-schema.sql
│ ├── lcbp3-v1.7.0-seed.sql
│ ├── data-dictionary-v1.7.0.md
│ └── ...
└── 09-history/ # Archived Implementations (9 files)
└── ...
── 99-archives/ # ประวัติการทำงานและ Tasks เก่า
├── history/
├── tasks/
└── obsolete-specs/
```
### 📋 หมวดหมู่เอกสาร
| หมวด | วัตถุประสงค์ | ผู้ดูแล |
| --------------------- | ----------------------------- | ----------------------------- |
| **00-overview** | ภาพรวมโครงการและคำศัพท์ | Project Manager |
| **01-requirements** | ข้อกำหนดฟังก์ชันและระบบ | Business Analyst + Tech Lead |
| **02-architecture** | สถาปัตยกรรมและการออกแบบ | Tech Lead + Architects |
| **03-implementation** | แผนการพัฒนาและ Implementation | Development Team Leads |
| **04-operations** | Deployment และ Operations | DevOps Team |
| **05-decisions** | Architecture Decision Records | Tech Lead + Senior Developers |
| **06-tasks** | Active Tasks & Progress | All Team Members |
| **07-database** | Database Schema & Seed Data | Backend Lead + DBA |
| **09-history** | Archived Implementations | Tech Lead |
| ----------------------------- | ----------------------------- | ----------------------------- |
| **00-Overview** | ภาพรวมโครงการและคำศัพท์ | Project Manager |
| **01-Requirements** | ข้อกำหนดฟังก์ชันและระบบ | Business Analyst + Tech Lead |
| **02-Architecture** | สถาปัตยกรรมและการออกแบบ | Tech Lead + Architects |
| **03-Data-and-Storage** | Database Schema & Seed Data | Backend Lead + DBA |
| **04-Infrastructure-OPS** | Deployment และ Operations | DevOps Team |
| **05-Engineering-Guidelines** | แผนการพัฒนาและ Implementation | Development Team Leads |
| **06-Decision-Records** | Architecture Decision Records | Tech Lead + Senior Developers |
| **99-archives** | Archived / Tasks | All Team Members |
---
@@ -184,8 +165,8 @@ POST /api/correspondences
---
**Last Updated**: 2025-11-30
**Version**: 1.4.5
**Last Updated**: 2026-02-24
**Version**: 1.8.0
**Status**: Draft | Review | Approved
```
@@ -222,7 +203,7 @@ git checkout -b spec/adr/file-storage-strategy
```bash
# แก้ไขไฟล์ที่เกี่ยวข้อง
vim specs/01-requirements/03.2-correspondence.md
vim specs/01-Requirements/01-03-modules/03-correspondence.md
# ตรวจสอบ markdown syntax
pnpm run lint:markdown
@@ -526,10 +507,10 @@ graph LR
```markdown
## Related Documents
- Requirements: [03.2-correspondence.md](./03.2-correspondence.md)
- Architecture: [system-architecture.md](../02-architecture/system-architecture.md)
- ADR: [ADR-001: Workflow Engine](../05-decisions/001-workflow-engine.md)
- Implementation: [Backend Plan](../../docs/2_Backend_Plan_V1_4_5.md)
- Requirements: [03.2-correspondence.md](../01-Requirements/01-03-modules/03-correspondence.md)
- Architecture: [02-02-software-architecture.md](../02-Architecture/02-02-software-architecture.md)
- ADR: [ADR-001-unified-workflow.md](../06-Decision-Records/ADR-001-unified-workflow.md)
- Implementation: [05-02-backend-guidelines.md](../05-Engineering-Guidelines/05-02-backend-guidelines.md)
````
### 4. Version Control
@@ -545,14 +526,14 @@ graph LR
| 1.1.0 | 2025-02-20 | Jane Smith | Add CC support |
| 1.2.0 | 2025-03-10 | John Doe | Update workflow |
**Current Version**: 1.2.0
**Current Version**: 1.8.0
**Status**: Approved
**Last Updated**: 2025-03-10
**Last Updated**: 2026-02-24
```
### 5. ใช้ Consistent Terminology
อ้างอิงจาก [glossary.md](./specs/00-overview/glossary.md) เสมอ
อ้างอิงจาก [glossary.md](./specs/00-Overview/00-02-glossary.md) เสมอ
```markdown
- ✅ ใช้: "Correspondence" (เอกสารโต้ตอบ)
@@ -625,7 +606,7 @@ Create `.markdownlint.json`:
### คำถามเกี่ยวกับ Specs
1. **ตรวจสอบเอกสารที่มีอยู่**: [specs/](./specs/)
2. **ดู Glossary**: [specs/00-overview/glossary.md](./specs/00-overview/glossary.md)
2. **ดู Glossary**: [00-02-glossary.md](./specs/00-Overview/00-02-glossary.md)
3. **ค้นหา Issues**: [Gitea Issues](https://git.np-dms.work/lcbp3/lcbp3-dms/issues)
4. **ถาม Team**: [ช่องทางการติดต่อ]

Binary file not shown.

View File

@@ -4,20 +4,20 @@
>
> ระบบบริหารจัดการเอกสารโครงการแบบครบวงจร สำหรับโครงการก่อสร้างท่าเรือแหลมฉบังระยะที่ 3
[![Version](https://img.shields.io/badge/version-1.7.0-blue.svg)](./CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-1.8.0-blue.svg)](./CHANGELOG.md)
[![License](https://img.shields.io/badge/license-Internal-red.svg)]()
[![Status](https://img.shields.io/badge/status-Production%20Ready-brightgreen.svg)]()
---
## 📈 Current Status (As of 2025-12-18)
## 📈 Current Status (As of 2026-02-24)
**Overall Progress: ~97% Feature Complete - Production Ready Preparation**
**Overall Progress: ~98% Feature Complete - Production Ready Preparation**
-**Backend**: Core modules implemented, refactoring for v1.7.0 Schema
-**Frontend**: UI tasks completed (100%), integrating new v1.7.0 features
-**Database**: Schema v1.7.0 active (Stabilized for Production)
-**Documentation**: Comprehensive specs/ at v1.7.0
-**Backend**: Core modules implemented, refactoring for v1.8.0 Schema
-**Frontend**: UI tasks completed (100%), integrating new v1.8.0 features
-**Database**: Schema v1.8.0 active (Stabilized for Production)
-**Documentation**: Comprehensive specs/ at v1.8.0
-**Admin Tools**: Unified Workflow & Advanced Numbering Config
- 🔄 **Testing**: E2E tests and UAT preparation
- 📋 **Next**: Final Security Audit & Deployment
@@ -269,23 +269,21 @@ lcbp3-dms/
│ ├── types/ # TypeScript definitions
│ └── package.json
├── specs/ # 📘 Project Specifications (v1.5.1)
│ ├── 00-overview/ # Project overview & glossary
│ ├── 01-requirements/ # Functional requirements (21 docs)
│ ├── 02-architecture/ # System architecture
│ ├── 03-implementation/ # Implementation guidelines
│ ├── 04-operations/ # Deployment & operations
│ ├── 05-decisions/ # ADRs (17 decisions)
│ ├── 06-tasks/ # Active tasks & progress
── 07-database/ # Schema v1.5.1 & seed data
│ └── 09-history/ # Archived implementations
├── specs/ # 📘 Project Specifications (v1.8.0)
│ ├── 00-Overview/ # ภาพรวมระบบและแบบย่อ
│ ├── 01-Requirements/ # Business Requirements & กฎระเบียบ (21 docs)
│ ├── 02-Architecture/ # สถาปัตยกรรมระบบ
│ ├── 03-Data-and-Storage/ # โครงสร้างฐานข้อมูล v1.8.0 & Data Dictionary
│ ├── 04-Infrastructure-OPS/ # การเตรียม Operations & Infrastructure
│ ├── 05-Engineering-Guidelines/ # มาตรฐานการพัฒนาสำหรับโปรแกรมเมอร์
│ ├── 06-Decision-Records/ # สรุปเหตุผลด้านสถาปัตยกรรม (ADRs)
── 99-archives/ # ประวัติการทำงานและ Tasks เก่า
├── docs/ # 📚 Legacy documentation
├── diagrams/ # 📊 Architecture diagrams
├── infrastructure/ # 🐳 Docker & Deployment configs
├── .gemini/ # 🤖 AI agent configuration
├── .agent/ # Agent workflows
├── .agents/ # Agent workflows and tools
├── GEMINI.md # AI coding guidelines
├── CONTRIBUTING.md # Contribution guidelines
├── CHANGELOG.md # Version history
@@ -299,21 +297,23 @@ lcbp3-dms/
### เอกสารหลัก (specs/ folder)
| เอกสาร | คำอธิบาย | โฟลเดอร์ |
| ------------------ | ------------------------------ | -------------------------- |
| **Overview** | ภาพรวมโครงการ, Glossary | `specs/00-overview/` |
| **Requirements** | ข้อกำหนดระบบและฟังก์ชันการทำงาน | `specs/01-requirements/` |
| **Architecture** | สถาปัตยกรรมระบบ, ADRs | `specs/02-architecture/` |
| **Implementation** | แนวทางการพัฒนา Backend/Frontend | `specs/03-implementation/` |
| **Database** | Schema v1.7.0 + Seed Data | `specs/07-database/` |
| ------------------- | ------------------------------ | ---------------------------------- |
| **Overview** | ภาพรวมโครงการ, Glossary | `specs/00-Overview/` |
| **Requirements** | ข้อกำหนดระบบและฟังก์ชันการทำงาน | `specs/01-Requirements/` |
| **Architecture** | สถาปัตยกรรมระบบ | `specs/02-Architecture/` |
| **Database** | Schema v1.8.0 + Seed Data | `specs/03-Data-and-Storage/` |
| **Ops & Deploy** | วิธีการนำระบบขึ้นเซิร์ฟเวอร์ | `specs/04-Infrastructure-OPS/` |
| **Guidelines** | แนวทางการพัฒนา Backend/Frontend | `specs/05-Engineering-Guidelines/` |
| **Decisions (ADR)** | เหตุผลการตัดสินใจทางสถาปัตยกรรม | `specs/06-Decision-Records/` |
### Schema & Seed Data
```bash
# Import schema
mysql -u root -p lcbp3_dev < specs/07-database/lcbp3-v1.7.0-schema.sql
mysql -u root -p lcbp3_dev < specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql
# Import seed data
mysql -u root -p lcbp3_dev < specs/07-database/lcbp3-v1.7.0-seed.sql
mysql -u root -p lcbp3_dev < specs/03-Data-and-Storage/lcbp3-v1.7.0-seed-basic.sql
```
### Legacy Documentation
@@ -401,12 +401,10 @@ pnpm test:e2e # Playwright E2E
### Security Best Practices
1. **ห้ามเก็บ Secrets ใน Git**
- ใช้ `.env` สำหรับ Development
- ใช้ `docker-compose.override.yml` (gitignored)
2. **Password Policy**
- ความยาวขั้นต่ำ: 8 ตัวอักษร
- ต้องมี uppercase, lowercase, number, special character
- เปลี่ยน password ทุก 90 วัน
@@ -533,6 +531,7 @@ This project is **Internal Use Only** - ลิขสิทธิ์เป็น
### Version 1.5.1 (Current - Dec 2025) ✅ **FEATURE COMPLETE**
**Backend (18 Modules - ~95%)**
- ✅ Core Infrastructure (Auth, RBAC, File Storage)
- ✅ Authentication & Authorization (JWT + CASL RBAC 4-Level)
- ✅ Correspondence Module (Master-Revision Pattern)
@@ -549,6 +548,7 @@ This project is **Internal Use Only** - ลิขสิทธิ์เป็น
- ✅ Swagger API Documentation
**Frontend (15 Tasks - 100%)**
- ✅ Complete UI Implementation (17 component groups)
- ✅ All Business Modules (Correspondence, RFA, Drawings)
- ✅ Admin Panel (10 routes including Workflow & Numbering Config)
@@ -558,22 +558,24 @@ This project is **Internal Use Only** - ลิขสิทธิ์เป็น
- ✅ Responsive Layout (Desktop & Mobile)
**Documentation**
- ✅ Complete specs/ v1.6.0 (21 requirements, 17 ADRs)
- ✅ Database Schema v1.6.0 with seed data
- ✅ Implementation & Operations Guides
### Version 1.7.0 (Current - Dec 2025)
### Version 1.8.0 (Current - Feb 2026)
**Schema & Core Stabilization**
-**Document Numbering V2**: Composite Keys, Reservations, Reset Scopes
-**Unified Workflow Engine**: Compiled DSL, Polymorphic Instances
-**Data Dictionary**: Complete Update to v1.7.0
- 🔄 **Backend Refactor**: Aligning services with new schema
- 📋 **E2E Test Coverage**: Playwright/Cypress rollout
**Schema & Documentation Realignment**
### Version 1.8.0+ (Planned - Q1 2026)
-**Specs Refactoring**: Merged infrastructure docs, reorganized `specs` tree to standard structure.
-**Database & Models**: Fully aligned Next.js features and TanStack Query with real v1.8.0 implementation.
-**Clean Code**: Comprehensive purge of `any` types from Frontend and robust Error Handling.
- 📋 **Deployment Readiness**: Preparing robust healthcheck and Nginx configurations for QNAP/ASUSTOR.
### Version 1.9.0+ (Planned)
**Production Enhancements**
- 📊 Advanced Reporting & Analytics Dashboard
- 🔔 Enhanced Notifications (Real-time WebSocket)
- 📈 Prometheus Metrics & Grafana Dashboards

View File

@@ -1,100 +0,0 @@
at Readable.push (node:internal/streams/readable:392:5) {
query: 'DELETE FROM `notifications` WHERE (`is_read` = ? AND `createdAt` < ?)',
parameters: [
true,
2026-01-17T17:00:00.024Z
],
driverError: Error: Unknown column 'createdAt' in 'WHERE'
at Packet.asError (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packets/packet.js:740:17)
at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:29:26)
at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)
at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)
at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)
at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)
at Socket.emit (node:events:519:28)
at addChunk (node:internal/streams/readable:561:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
at Readable.push (node:internal/streams/readable:392:5) {
code: 'ER_BAD_FIELD_ERROR',
errno: 1054,
sqlState: '42S22',
sqlMessage: "Unknown column 'createdAt' in 'WHERE'",
sql: "DELETE FROM `notifications` WHERE (`is_read` = true AND `createdAt` < '2026-01-18 00:00:00.024')"
},
code: 'ER_BAD_FIELD_ERROR',
errno: 1054,
sqlState: '42S22',
sqlMessage: "Unknown column 'createdAt' in 'WHERE'",
sql: "DELETE FROM `notifications` WHERE (`is_read` = true AND `createdAt` < '2026-01-18 00:00:00.024')"
}
[Nest] 1 - 02/17/2026, 12:00:00 AM LOG [FileCleanupService] No expired files found.
[Nest] 1 - 02/17/2026, 12:00:00 AM ERROR [NotificationCleanupService] Failed to cleanup notifications
[Nest] 1 - 02/17/2026, 12:00:00 AM ERROR [NotificationCleanupService] QueryFailedError: Unknown column 'createdAt' in 'WHERE'
at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_cb81dfd56f1203fe00eb0fec5dfcce08/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)
at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)
at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)
at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)
at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)
at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)
at Socket.emit (node:events:519:28)
at addChunk (node:internal/streams/readable:561:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
at Readable.push (node:internal/streams/readable:392:5) {
query: 'DELETE FROM `notifications` WHERE (`is_read` = ? AND `createdAt` < ?)',
parameters: [
true,
2026-01-17T17:00:00.038Z
],
driverError: Error: Unknown column 'createdAt' in 'WHERE'
at Packet.asError (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packets/packet.js:740:17)
at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:29:26)

View File

@@ -23,7 +23,7 @@
"seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts"
},
"dependencies": {
"@casl/ability": "^6.7.3",
"@casl/ability": "^6.7.5",
"@elastic/elasticsearch": "^8.11.1",
"@nestjs-modules/ioredis": "^2.0.2",
"@nestjs/axios": "^4.0.1",
@@ -130,5 +130,10 @@
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
},
"pnpm": {
"overrides": {
"fast-xml-parser": "^5.3.5"
}
}
}

BIN
bfg.jar

Binary file not shown.

View File

View File

@@ -1 +0,0 @@
# Mermaid diagrams

View File

@@ -42,24 +42,24 @@ interface FieldConfig {
label: string;
type: "text" | "textarea" | "checkbox" | "select";
required?: boolean;
options?: { label: string; value: any }[];
options?: { label: string; value: string | number | boolean }[];
}
interface GenericCrudTableProps {
interface GenericCrudTableProps<TEntity extends { id: number }> {
entityName: string;
queryKey: string[];
fetchFn: () => Promise<any>;
createFn: (data: any) => Promise<any>;
updateFn: (id: number, data: any) => Promise<any>;
deleteFn: (id: number) => Promise<any>;
columns: ColumnDef<any>[];
fetchFn: () => Promise<TEntity[]>;
createFn: (data: Record<string, unknown>) => Promise<TEntity>;
updateFn: (id: number, data: Record<string, unknown>) => Promise<TEntity>;
deleteFn: (id: number) => Promise<unknown>;
columns: ColumnDef<TEntity>[];
fields: FieldConfig[];
title?: string;
description?: string;
filters?: React.ReactNode;
}
export function GenericCrudTable({
export function GenericCrudTable<TEntity extends { id: number }>({
entityName,
queryKey,
fetchFn,
@@ -71,11 +71,11 @@ export function GenericCrudTable({
title,
description,
filters,
}: GenericCrudTableProps) {
}: GenericCrudTableProps<TEntity>) {
const queryClient = useQueryClient();
const [isOpen, setIsOpen] = useState(false);
const [editingItem, setEditingItem] = useState<any>(null);
const [formData, setFormData] = useState<any>({});
const [editingItem, setEditingItem] = useState<TEntity | null>(null);
const [formData, setFormData] = useState<Record<string, unknown>>({});
// Delete Dialog State
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
@@ -97,7 +97,7 @@ export function GenericCrudTable({
});
const updateMutation = useMutation({
mutationFn: ({ id, data }: { id: number; data: any }) => updateFn(id, data),
mutationFn: ({ id, data }: { id: number; data: Record<string, unknown> }) => updateFn(id, data),
onSuccess: () => {
toast.success(`${entityName} updated successfully`);
queryClient.invalidateQueries({ queryKey });
@@ -123,7 +123,7 @@ export function GenericCrudTable({
setIsOpen(true);
};
const handleEdit = (item: any) => {
const handleEdit = (item: TEntity) => {
setEditingItem(item);
setFormData({ ...item });
setIsOpen(true);
@@ -155,8 +155,8 @@ export function GenericCrudTable({
}
};
const handleChange = (field: string, value: any) => {
setFormData((prev: any) => ({ ...prev, [field]: value }));
const handleChange = (field: string, value: unknown) => {
setFormData((prev: Record<string, unknown>) => ({ ...prev, [field]: value }));
};
// Add default Actions column if not present
@@ -165,7 +165,7 @@ export function GenericCrudTable({
{
id: "actions",
header: "Actions",
cell: ({ row }: { row: any }) => (
cell: ({ row }: { row: { original: TEntity } }) => (
<div className="flex gap-2 justify-end">
<Button
variant="ghost"
@@ -239,7 +239,7 @@ export function GenericCrudTable({
{field.type === "textarea" ? (
<Textarea
id={field.name}
value={formData[field.name] || ""}
value={(formData[field.name] as string) || ""}
onChange={(e) => handleChange(field.name, e.target.value)}
required={field.required}
/>
@@ -266,7 +266,7 @@ export function GenericCrudTable({
</SelectTrigger>
<SelectContent>
{field.options?.map((opt) => (
<SelectItem key={opt.value} value={opt.value.toString()}>
<SelectItem key={(opt.value as string | number)} value={opt.value.toString()}>
{opt.label}
</SelectItem>
))}
@@ -276,7 +276,7 @@ export function GenericCrudTable({
<Input
id={field.name}
type="text"
value={formData[field.name] || ""}
value={(formData[field.name] as string) || ""}
onChange={(e) => handleChange(field.name, e.target.value)}
required={field.required}
/>

View File

@@ -14,6 +14,14 @@ import {
} from "@/components/ui/popover";
import { useSearchSuggestions } from "@/hooks/use-search";
/** Search suggestion item returned from the API */
interface SearchSuggestion {
id: string | number;
type: string;
title: string;
documentNumber?: string;
}
function useDebounceValue<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
@@ -87,7 +95,7 @@ export function GlobalSearch() {
<CommandList>
{suggestions && suggestions.length > 0 && (
<CommandGroup heading="Suggestions">
{suggestions.map((item: any) => (
{(suggestions as SearchSuggestion[]).map((item) => (
<CommandItem
key={`${item.type}-${item.id}`}
onSelect={() => {

View File

@@ -14,6 +14,7 @@ import { Badge } from "@/components/ui/badge";
import { useNotifications, useMarkNotificationRead } from "@/hooks/use-notification";
import { formatDistanceToNow } from "date-fns";
import { useRouter } from "next/navigation";
import type { Notification } from "@/types/notification";
export function NotificationsDropdown() {
const router = useRouter();
@@ -23,7 +24,7 @@ export function NotificationsDropdown() {
const notifications = data?.items || [];
const unreadCount = data?.unreadCount || 0;
const handleNotificationClick = (notification: any) => {
const handleNotificationClick = (notification: Notification) => {
if (!notification.isRead) {
markAsRead.mutate(notification.notificationId);
}
@@ -62,7 +63,7 @@ export function NotificationsDropdown() {
</div>
) : (
<div className="max-h-96 overflow-y-auto">
{notifications.slice(0, 5).map((notification: any) => (
{notifications.slice(0, 5).map((notification: Notification) => (
<DropdownMenuItem
key={notification.notificationId}
className={`flex flex-col items-start p-3 cursor-pointer ${

View File

@@ -1,12 +1,13 @@
import { AuditLog, AuditLogQueryParams } from '@/lib/services/audit-log.service';
import { useQuery } from '@tanstack/react-query';
import { auditLogService, AuditLog } from '@/lib/services/audit-log.service';
import { auditLogService } from '@/lib/services/audit-log.service';
export const auditLogKeys = {
all: ['audit-logs'] as const,
list: (params: any) => [...auditLogKeys.all, 'list', params] as const,
list: (params?: AuditLogQueryParams) => [...auditLogKeys.all, 'list', params] as const,
};
export function useAuditLogs(params?: any) {
export function useAuditLogs(params?: AuditLogQueryParams) {
return useQuery<AuditLog[]>({
queryKey: auditLogKeys.list(params),
queryFn: () => auditLogService.getLogs(params),

View File

@@ -37,7 +37,7 @@ export const useNumberingMetrics = () => {
export const useNumberingAuditLogs = (params?: AuditQueryParams) => {
return useQuery({
queryKey: numberingKeys.auditLogs(params),
queryFn: () => documentNumberingService.getAuditLogs(params),
queryFn: () => documentNumberingService.getAuditLogs(),
});
};
@@ -75,7 +75,7 @@ export const useCancelNumbering = () => {
export const useBulkImportNumbering = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: FormData | any[]) => documentNumberingService.bulkImport(data),
mutationFn: (data: FormData | { documentNumber: string; projectId: number; sequenceNumber: number }[]) => documentNumberingService.bulkImport(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: numberingKeys.all });
},

View File

@@ -2,6 +2,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { projectService } from '@/lib/services/project.service';
import { CreateProjectDto, UpdateProjectDto, SearchProjectDto } from '@/types/dto/project/project.dto';
import { toast } from 'sonner';
import { getApiErrorMessage } from '@/types/api-error';
export const projectKeys = {
all: ['projects'] as const,
@@ -24,9 +25,9 @@ export function useCreateProject() {
toast.success("Project created successfully");
queryClient.invalidateQueries({ queryKey: projectKeys.all });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error("Failed to create project", {
description: error.response?.data?.message || "Unknown error"
description: getApiErrorMessage(error, "Unknown error")
});
}
});
@@ -40,9 +41,9 @@ export function useUpdateProject() {
toast.success("Project updated successfully");
queryClient.invalidateQueries({ queryKey: projectKeys.all });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error("Failed to update project", {
description: error.response?.data?.message || "Unknown error"
description: getApiErrorMessage(error, "Unknown error")
});
}
});
@@ -56,9 +57,9 @@ export function useDeleteProject() {
toast.success("Project deleted successfully");
queryClient.invalidateQueries({ queryKey: projectKeys.all });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error("Failed to delete project", {
description: error.response?.data?.message || "Unknown error"
description: getApiErrorMessage(error, "Unknown error")
});
}
});

View File

@@ -1,5 +1,8 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { masterDataService } from '@/lib/services/master-data.service';
import type { CreateDisciplineDto } from '@/types/dto/master/discipline.dto';
import type { CreateRfaTypeDto, UpdateRfaTypeDto } from '@/types/dto/master/rfa-type.dto';
import type { CreateCorrespondenceTypeDto, UpdateCorrespondenceTypeDto } from '@/types/dto/master/correspondence-type.dto';
export const referenceDataKeys = {
all: ['reference-data'] as const,
@@ -19,7 +22,7 @@ export const useRfaTypes = (contractId?: number) => {
export const useCreateRfaType = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: any) => masterDataService.createRfaType(data),
mutationFn: (data: CreateRfaTypeDto) => masterDataService.createRfaType(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['reference-data', 'rfaTypes'] });
},
@@ -29,7 +32,7 @@ export const useCreateRfaType = () => {
export const useUpdateRfaType = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: any }) => masterDataService.updateRfaType(id, data),
mutationFn: ({ id, data }: { id: number; data: UpdateRfaTypeDto }) => masterDataService.updateRfaType(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['reference-data', 'rfaTypes'] });
},
@@ -57,7 +60,7 @@ export const useDisciplines = (contractId?: number) => {
export const useCreateDiscipline = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: any) => masterDataService.createDiscipline(data),
mutationFn: (data: CreateDisciplineDto) => masterDataService.createDiscipline(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['reference-data', 'disciplines'] });
},
@@ -85,7 +88,7 @@ export const useCorrespondenceTypes = () => {
export const useCreateCorrespondenceType = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: any) => masterDataService.createCorrespondenceType(data),
mutationFn: (data: CreateCorrespondenceTypeDto) => masterDataService.createCorrespondenceType(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['reference-data', 'correspondenceTypes'] });
},
@@ -95,7 +98,7 @@ export const useCreateCorrespondenceType = () => {
export const useUpdateCorrespondenceType = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: any }) => masterDataService.updateCorrespondenceType(id, data),
mutationFn: ({ id, data }: { id: number; data: UpdateCorrespondenceTypeDto }) => masterDataService.updateCorrespondenceType(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['reference-data', 'correspondenceTypes'] });
},

View File

@@ -3,6 +3,7 @@ import { rfaService } from '@/lib/services/rfa.service';
import { SearchRfaDto, CreateRfaDto, UpdateRfaDto } from '@/types/dto/rfa/rfa.dto';
import { WorkflowActionDto } from '@/lib/services/rfa.service';
import { toast } from 'sonner';
import { getApiErrorMessage } from '@/types/api-error';
// Keys
export const rfaKeys = {
@@ -42,9 +43,9 @@ export function useCreateRFA() {
toast.success('RFA created successfully');
queryClient.invalidateQueries({ queryKey: rfaKeys.lists() });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error('Failed to create RFA', {
description: error.response?.data?.message || 'Something went wrong',
description: getApiErrorMessage(error, 'Something went wrong'),
});
},
});
@@ -61,9 +62,9 @@ export function useUpdateRFA() {
queryClient.invalidateQueries({ queryKey: rfaKeys.detail(id) });
queryClient.invalidateQueries({ queryKey: rfaKeys.lists() });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error('Failed to update RFA', {
description: error.response?.data?.message || 'Something went wrong',
description: getApiErrorMessage(error, 'Something went wrong'),
});
},
});
@@ -80,9 +81,9 @@ export function useProcessRFA() {
queryClient.invalidateQueries({ queryKey: rfaKeys.detail(id) });
queryClient.invalidateQueries({ queryKey: rfaKeys.lists() });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error('Failed to process workflow', {
description: error.response?.data?.message || 'Something went wrong',
description: getApiErrorMessage(error, 'Something went wrong'),
});
},
});

View File

@@ -1,11 +1,12 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { userService } from '@/lib/services/user.service';
import { CreateUserDto, UpdateUserDto, SearchUserDto } from '@/types/user'; // Ensure types exist
import { CreateUserDto, UpdateUserDto, SearchUserDto } from '@/types/user';
import { toast } from 'sonner';
import { getApiErrorMessage } from '@/types/api-error';
export const userKeys = {
all: ['users'] as const,
list: (params: any) => [...userKeys.all, 'list', params] as const,
list: (params?: SearchUserDto) => [...userKeys.all, 'list', params] as const,
detail: (id: number) => [...userKeys.all, 'detail', id] as const,
};
@@ -31,9 +32,9 @@ export function useCreateUser() {
toast.success("User created successfully");
queryClient.invalidateQueries({ queryKey: userKeys.all });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error("Failed to create user", {
description: error.response?.data?.message || "Unknown error"
description: getApiErrorMessage(error, "Unknown error")
});
}
});
@@ -47,9 +48,9 @@ export function useUpdateUser() {
toast.success("User updated successfully");
queryClient.invalidateQueries({ queryKey: userKeys.all });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error("Failed to update user", {
description: error.response?.data?.message || "Unknown error"
description: getApiErrorMessage(error, "Unknown error")
});
}
});
@@ -63,9 +64,9 @@ export function useDeleteUser() {
toast.success("User deleted successfully");
queryClient.invalidateQueries({ queryKey: userKeys.all });
},
onError: (error: any) => {
onError: (error: unknown) => {
toast.error("Failed to delete user", {
description: error.response?.data?.message || "Unknown error"
description: getApiErrorMessage(error, "Unknown error")
});
}
});

View File

@@ -3,6 +3,7 @@ import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import { z } from "zod";
import type { User } from "next-auth";
import type { JWT } from "next-auth/jwt";
// Schema for input validation
const loginSchema = z.object({
@@ -17,12 +18,12 @@ function getJwtExpiry(token: string): number {
try {
const payload = JSON.parse(atob(token.split('.')[1]));
return payload.exp * 1000; // Convert to ms
} catch (e) {
} catch {
return Date.now(); // If invalid, treat as expired
}
}
async function refreshAccessToken(token: any) {
async function refreshAccessToken(token: JWT) {
try {
const response = await fetch(`${baseUrl}/auth/refresh`, {
method: "POST",

View File

@@ -1,4 +1,5 @@
import apiClient from "@/lib/api/client";
import { AuditQueryParams } from '@/types/dto/numbering.dto';
export interface AuditLog {
auditId: string;
@@ -12,16 +13,18 @@ export interface AuditLog {
severity: string;
entityType?: string;
entityId?: string;
detailsJson?: any;
detailsJson?: Record<string, unknown>;
ipAddress?: string;
userAgent?: string;
createdAt: string;
}
export type AuditLogQueryParams = AuditQueryParams;
export const auditLogService = {
getLogs: async (params?: any) => {
const response = await apiClient.get<any>("/audit-logs", { params });
getLogs: async (params?: AuditLogQueryParams) => {
const response = await apiClient.get<{ data: AuditLog[] } | AuditLog[]>("/audit-logs", { params });
// Support both wrapped and unwrapped scenarios
return response.data.data || response.data;
return (response.data as { data: AuditLog[] }).data ?? response.data;
},
};

View File

@@ -25,7 +25,7 @@ export const correspondenceService = {
return response.data;
},
update: async (id: string | number, data: any) => {
update: async (id: string | number, data: Partial<CreateCorrespondenceDto>) => {
const response = await apiClient.put(`/correspondences/${id}`, data);
return response.data;
},

View File

@@ -4,9 +4,16 @@ import {
ManualOverrideDto,
VoidReplaceDto,
CancelNumberDto,
AuditQueryParams
} from "@/types/dto/numbering.dto";
/** A bulk-import record row */
export interface BulkImportRecord {
documentNumber: string;
projectId: number;
sequenceNumber: number;
[key: string]: unknown;
}
export const documentNumberingService = {
// --- Admin Dashboard Metrics ---
getMetrics: async (): Promise<NumberingMetrics> => {
@@ -19,7 +26,7 @@ export const documentNumberingService = {
await apiClient.post("/admin/document-numbering/manual-override", dto);
},
voidAndReplace: async (dto: VoidReplaceDto): Promise<any> => {
voidAndReplace: async (dto: VoidReplaceDto): Promise<{ documentNumber: string }> => {
const response = await apiClient.post("/admin/document-numbering/void-and-replace", dto);
return response.data;
},
@@ -28,7 +35,7 @@ export const documentNumberingService = {
await apiClient.post("/admin/document-numbering/cancel", dto);
},
bulkImport: async (data: FormData | any[]): Promise<any> => {
bulkImport: async (data: FormData | BulkImportRecord[]): Promise<{ imported: number; errors: string[] }> => {
const isFormData = data instanceof FormData;
const config = isFormData ? { headers: { "Content-Type": "multipart/form-data" } } : {};
const response = await apiClient.post("/admin/document-numbering/bulk-import", data, config);
@@ -36,7 +43,7 @@ export const documentNumberingService = {
},
// --- Audit Logs ---
getAuditLogs: async (params?: AuditQueryParams) => {
getAuditLogs: async () => {
// NOTE: endpoint might be merged with metrics or separate
// Currently controller has getMetrics returning audit logs too.
// But if we want separate pagination later:

View File

@@ -64,7 +64,7 @@ export const jsonSchemaService = {
/**
* (Optional) ตรวจสอบความถูกต้องของข้อมูลกับ Schema ฝั่ง Server
*/
validate: async (code: string, data: any) => {
validate: async (code: string, data: Record<string, unknown>) => {
// POST /json-schemas/validate
const response = await apiClient.post(`/json-schemas/validate`, {
schemaCode: code,

View File

@@ -6,6 +6,8 @@ import { CreateTagDto, UpdateTagDto, SearchTagDto } from "@/types/dto/master/tag
import { CreateDisciplineDto } from "@/types/dto/master/discipline.dto";
import { CreateSubTypeDto } from "@/types/dto/master/sub-type.dto";
import { SaveNumberFormatDto } from "@/types/dto/master/number-format.dto";
import { CreateRfaTypeDto, UpdateRfaTypeDto } from "@/types/dto/master/rfa-type.dto";
import { CreateCorrespondenceTypeDto, UpdateCorrespondenceTypeDto } from "@/types/dto/master/correspondence-type.dto";
import { Organization } from "@/types/organization";
import {
CreateOrganizationDto,
@@ -137,21 +139,11 @@ export const masterDataService = {
},
/** สร้างประเภท RFA ใหม่ */
createRfaType: async (data: any) => {
// Note: Assuming endpoint is /master/rfa-types (POST)
// Currently RfaController handles /rfas, but master data usually goes to MasterController or dedicated
// The previous implementation used direct apiClient calls in the page.
// Let's assume we use the endpoint we just updated in MasterController which is GET only?
// Wait, MasterController doesn't have createRfaType.
// Let's check where RFA Types are created. RfaController creates RFAs (documents).
// RFA Types are likely master data.
// I need to add create/update/delete endpoints for RFA Types to MasterController if they don't exist.
// Checking MasterController again... it DOES NOT have createRfaType.
// I will add them to MasterController first.
createRfaType: async (data: CreateRfaTypeDto) => {
return apiClient.post("/master/rfa-types", data).then(res => res.data);
},
updateRfaType: async (id: number, data: any) => {
updateRfaType: async (id: number, data: UpdateRfaTypeDto) => {
return apiClient.patch(`/master/rfa-types/${id}`, data).then(res => res.data);
},
@@ -167,11 +159,11 @@ export const masterDataService = {
return response.data.data || response.data;
},
createCorrespondenceType: async (data: any) => {
createCorrespondenceType: async (data: CreateCorrespondenceTypeDto) => {
return apiClient.post("/master/correspondence-types", data).then(res => res.data);
},
updateCorrespondenceType: async (id: number, data: any) => {
updateCorrespondenceType: async (id: number, data: UpdateCorrespondenceTypeDto) => {
return apiClient.patch(`/master/correspondence-types/${id}`, data).then(res => res.data);
},

View File

@@ -16,8 +16,8 @@ export interface Session {
export const sessionService = {
getActiveSessions: async () => {
const response = await apiClient.get<any>('/auth/sessions');
return response.data.data || response.data;
const response = await apiClient.get<Session[] | { data: Session[] }>('/auth/sessions');
return (response.data as { data: Session[] }).data ?? response.data;
},
revokeSession: async (sessionId: number) => {

View File

@@ -1,54 +1,62 @@
import apiClient from "@/lib/api/client";
import { CreateUserDto, UpdateUserDto, SearchUserDto, User } from "@/types/user";
const transformUser = (user: any): User => {
/** Raw API user shape (before transform) */
interface RawUser {
user_id?: number;
userId?: number;
assignments?: Array<{ role: unknown }>;
[key: string]: unknown;
}
const transformUser = (user: RawUser): User => {
return {
...user,
userId: user.user_id,
roles: user.assignments?.map((a: any) => a.role) || [],
...(user as unknown as User),
userId: (user.user_id ?? user.userId) as number,
roles: (user.assignments?.map((a) => a.role) ?? []) as User['roles'],
};
};
/** Paginated or unwrapped response shape */
type UserListResponse = User[] | { data: User[] | { data: User[] } };
export const userService = {
getAll: async (params?: SearchUserDto) => {
const response = await apiClient.get<any>("/users", { params });
const response = await apiClient.get<UserListResponse>("/users", { params });
// Handle both paginated and non-paginated responses
let rawData = response.data?.data || response.data;
// If paginated (has .data property which is array)
if (rawData && Array.isArray(rawData.data)) {
rawData = rawData.data;
let rawData: RawUser[] | unknown = response.data;
if (rawData && !Array.isArray(rawData) && 'data' in (rawData as object)) {
rawData = (rawData as { data: unknown }).data;
}
// If still not array (e.g. error or empty), default to []
if (!Array.isArray(rawData)) {
return [];
if (rawData && !Array.isArray(rawData) && typeof rawData === 'object' && 'data' in (rawData as object)) {
rawData = (rawData as { data: unknown }).data;
}
if (!Array.isArray(rawData)) return [];
return rawData.map(transformUser);
return (rawData as RawUser[]).map(transformUser);
},
getRoles: async () => {
const response = await apiClient.get<any>("/users/roles");
if (response.data?.data) {
return response.data.data;
const response = await apiClient.get<{ data: unknown } | unknown>("/users/roles");
if (response.data && typeof response.data === 'object' && 'data' in (response.data as object)) {
return (response.data as { data: unknown }).data;
}
return response.data;
},
getById: async (id: number) => {
const response = await apiClient.get<User>(`/users/${id}`);
const response = await apiClient.get<RawUser>(`/users/${id}`);
return transformUser(response.data);
},
create: async (data: CreateUserDto) => {
const response = await apiClient.post<User>("/users", data);
const response = await apiClient.post<RawUser>("/users", data);
return transformUser(response.data);
},
update: async (id: number, data: UpdateUserDto) => {
const response = await apiClient.put<User>(`/users/${id}`, data);
const response = await apiClient.put<RawUser>(`/users/${id}`, data);
return transformUser(response.data);
},

View File

@@ -2,10 +2,13 @@
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
/** A draft can hold any serializable form data — typed as unknown for strictness */
type DraftValue = Record<string, unknown>;
interface DraftState {
drafts: Record<string, any>;
saveDraft: (key: string, data: any) => void;
getDraft: (key: string) => any;
drafts: Record<string, DraftValue>;
saveDraft: (key: string, data: DraftValue) => void;
getDraft: (key: string) => DraftValue | undefined;
clearDraft: (key: string) => void;
}

View File

@@ -0,0 +1,20 @@
// Shared API error type for Axios-based error handling in TanStack Query
export interface ApiErrorResponse {
message?: string;
error?: string;
statusCode?: number;
}
/** Axios-compatible error with typed response data */
export interface ApiError extends Error {
response?: {
data?: ApiErrorResponse;
status?: number;
};
}
/** Extract human-readable message from API error */
export function getApiErrorMessage(error: unknown, fallback = 'An unexpected error occurred'): string {
const apiError = error as ApiError;
return apiError?.response?.data?.message ?? apiError?.message ?? fallback;
}

View File

@@ -30,7 +30,7 @@ export interface CorrespondenceRevision {
statusCode: string;
statusName: string;
};
details?: any;
details?: Record<string, unknown> | null;
attachments?: Attachment[];
createdAt: string;
@@ -80,7 +80,7 @@ export interface CreateCorrespondenceDto {
remarks?: string;
dueDate?: string;
description?: string;
details?: Record<string, any>;
details?: Record<string, unknown>;
isInternal?: boolean;
originatorId?: number;
recipients?: { organizationId: number; type: 'TO' | 'CC' }[];

View File

@@ -7,7 +7,7 @@ export interface CreateContractDto {
endDate?: string;
}
export interface UpdateContractDto extends Partial<CreateContractDto> {}
export type UpdateContractDto = Partial<CreateContractDto>;
export interface SearchContractDto {
search?: string;

View File

@@ -29,7 +29,7 @@ export interface CreateCorrespondenceDto {
dueDate?: string;
/** ข้อมูล JSON เฉพาะประเภท (เช่น RFI question, RFA details) */
details?: Record<string, any>;
details?: Record<string, unknown>;
/** เอกสารภายในหรือไม่ (True = ภายใน) */
isInternal?: boolean;

View File

@@ -25,7 +25,7 @@ export interface CreateContractDrawingDto {
}
// --- Update (Partial) ---
export interface UpdateContractDrawingDto extends Partial<CreateContractDrawingDto> {}
export type UpdateContractDrawingDto = Partial<CreateContractDrawingDto>;
// --- Search ---
export interface SearchContractDrawingDto {

View File

@@ -9,14 +9,14 @@ export interface CreateJsonSchemaDto {
version?: number;
/** โครงสร้าง JSON Schema (Standard Format) */
schemaDefinition: Record<string, any>;
schemaDefinition: Record<string, unknown>;
/** สถานะการใช้งาน */
isActive?: boolean;
}
// --- Update (Partial) ---
export interface UpdateJsonSchemaDto extends Partial<CreateJsonSchemaDto> {}
export type UpdateJsonSchemaDto = Partial<CreateJsonSchemaDto>;
// --- Search ---
export interface SearchJsonSchemaDto {

View File

@@ -0,0 +1,24 @@
// File: src/types/dto/master/correspondence-type.dto.ts
export interface CreateCorrespondenceTypeDto {
/** ชื่อประเภทเอกสาร (เช่น 'Letter', 'RFA') */
typeName: string;
/** รหัสประเภทเอกสาร (เช่น 'LTR', 'RFA') */
typeCode: string;
/** มีการออกเลขเอกสารอัตโนมัติหรือไม่ */
hasNumbering?: boolean;
/** สถานะการใช้งาน (Default: true) */
isActive?: boolean;
}
export type UpdateCorrespondenceTypeDto = Partial<CreateCorrespondenceTypeDto>;
export interface SearchCorrespondenceTypeDto {
search?: string;
isActive?: boolean;
page?: number;
limit?: number;
}

View File

@@ -0,0 +1,21 @@
// File: src/types/dto/master/rfa-type.dto.ts
export interface CreateRfaTypeDto {
/** ชื่อประเภท RFA (เช่น 'Drawing Approval') */
typeName: string;
/** รหัสประเภท RFA (เช่น 'DWG', 'MAT') */
typeCode: string;
/** สถานะการใช้งาน (Default: true) */
isActive?: boolean;
}
export type UpdateRfaTypeDto = Partial<CreateRfaTypeDto>;
export interface SearchRfaTypeDto {
search?: string;
isActive?: boolean;
page?: number;
limit?: number;
}

View File

@@ -8,7 +8,7 @@ export interface CreateTagDto {
description?: string;
}
export interface UpdateTagDto extends Partial<CreateTagDto> {}
export type UpdateTagDto = Partial<CreateTagDto>;
export interface SearchTagDto {
/** คำค้นหา (ชื่อ Tag หรือ คำอธิบาย) */

View File

@@ -1,6 +1,15 @@
import type { AuditLog } from '@/lib/services/audit-log.service';
export interface AuditErrorRecord {
code: string;
message: string;
timestamp: string;
context?: Record<string, unknown>;
}
export interface NumberingMetrics {
audit: any[]; // Replace with specific AuditLog type if available
errors: any[]; // Replace with specific ErrorLog type
audit: AuditLog[];
errors: AuditErrorRecord[];
}
export interface ManualOverrideDto {

View File

@@ -13,7 +13,7 @@ export interface CreateProjectDto {
}
// --- Update (Partial) ---
export interface UpdateProjectDto extends Partial<CreateProjectDto> {}
export type UpdateProjectDto = Partial<CreateProjectDto>;
// --- Search ---
export interface SearchProjectDto {

View File

@@ -37,7 +37,7 @@ export interface CreateRfaDto {
}
// --- Update (Partial) ---
export interface UpdateRfaDto extends Partial<CreateRfaDto> {}
export type UpdateRfaDto = Partial<CreateRfaDto>;
// --- Search ---
export interface SearchRfaDto {

View File

@@ -25,7 +25,7 @@ export interface CreateTransmittalItemDto {
}
// --- Update (Partial) ---
export interface UpdateTransmittalDto extends Partial<CreateTransmittalDto> {}
export type UpdateTransmittalDto = Partial<CreateTransmittalDto>;
// --- Search ---
export interface SearchTransmittalDto {

Some files were not shown because too many files have changed in this diff Show More