@tekyzinc/gsd-t 2.46.11 → 2.50.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +22 -2
- package/bin/debug-ledger.js +193 -0
- package/bin/gsd-t.js +259 -1
- package/commands/gsd-t-debug.md +26 -1
- package/commands/gsd-t-execute.md +31 -3
- package/commands/gsd-t-help.md +18 -2
- package/commands/gsd-t-integrate.md +16 -0
- package/commands/gsd-t-quick.md +18 -1
- package/commands/gsd-t-test-sync.md +5 -1
- package/commands/gsd-t-verify.md +6 -1
- package/commands/gsd-t-wave.md +26 -0
- package/docs/GSD-T-README.md +83 -1
- package/docs/architecture.md +9 -1
- package/docs/requirements.md +30 -0
- package/package.json +1 -1
- package/templates/CLAUDE-global.md +19 -2
- package/templates/stacks/_security.md +243 -0
- package/templates/stacks/desktop.ini +2 -0
- package/templates/stacks/docker.md +202 -0
- package/templates/stacks/firebase.md +166 -0
- package/templates/stacks/flutter.md +205 -0
- package/templates/stacks/github-actions.md +201 -0
- package/templates/stacks/graphql.md +216 -0
- package/templates/stacks/neo4j.md +218 -0
- package/templates/stacks/nextjs.md +184 -0
- package/templates/stacks/node-api.md +196 -0
- package/templates/stacks/playwright.md +528 -0
- package/templates/stacks/postgresql.md +225 -0
- package/templates/stacks/python.md +243 -0
- package/templates/stacks/react-native.md +216 -0
- package/templates/stacks/react.md +293 -0
- package/templates/stacks/redux.md +193 -0
- package/templates/stacks/rest-api.md +202 -0
- package/templates/stacks/supabase.md +188 -0
- package/templates/stacks/tailwind.md +169 -0
- package/templates/stacks/typescript.md +176 -0
- package/templates/stacks/vite.md +176 -0
- package/templates/stacks/vue.md +189 -0
- package/templates/stacks/zustand.md +203 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Vue Standards
|
|
2
|
+
|
|
3
|
+
These rules are MANDATORY. Violations fail the task. No exceptions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Composition API
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
MANDATORY:
|
|
11
|
+
├── Use <script setup> (Composition API) — NEVER Options API for new code
|
|
12
|
+
├── Use ref() for primitives, reactive() for objects
|
|
13
|
+
├── Use computed() for derived values — NEVER store derived data in ref
|
|
14
|
+
├── Use composables (useXxx) for reusable logic — extract from components
|
|
15
|
+
└── NEVER use this. — Composition API doesn't use it
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**BAD** — Options API:
|
|
19
|
+
```vue
|
|
20
|
+
<script>
|
|
21
|
+
export default {
|
|
22
|
+
data() { return { count: 0 }; },
|
|
23
|
+
methods: { increment() { this.count++; } },
|
|
24
|
+
};
|
|
25
|
+
</script>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**GOOD** — Composition API:
|
|
29
|
+
```vue
|
|
30
|
+
<script setup lang="ts">
|
|
31
|
+
import { ref } from 'vue';
|
|
32
|
+
const count = ref(0);
|
|
33
|
+
const increment = () => count.value++;
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. State Management — Pinia
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
MANDATORY:
|
|
43
|
+
├── Pinia for global state — not Vuex
|
|
44
|
+
├── One store per domain (useUserStore, useCartStore)
|
|
45
|
+
├── Use Setup Stores syntax (function-based) — matches Composition API
|
|
46
|
+
├── Server data: prefer VueQuery (@tanstack/vue-query) — not Pinia
|
|
47
|
+
└── NEVER mutate store state directly from components — use actions
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**GOOD**
|
|
51
|
+
```typescript
|
|
52
|
+
export const useAuthStore = defineStore('auth', () => {
|
|
53
|
+
const user = ref<User | null>(null);
|
|
54
|
+
const isLoggedIn = computed(() => !!user.value);
|
|
55
|
+
|
|
56
|
+
async function login(credentials: LoginCredentials) {
|
|
57
|
+
user.value = await authService.login(credentials);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function logout() {
|
|
61
|
+
user.value = null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { user, isLoggedIn, login, logout };
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 3. Component Design
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
MANDATORY:
|
|
74
|
+
├── Max 150 lines per SFC — extract sub-components
|
|
75
|
+
├── <script setup> → <template> → <style scoped> order
|
|
76
|
+
├── One component per .vue file
|
|
77
|
+
├── Props: use defineProps with TypeScript interface
|
|
78
|
+
├── Emits: use defineEmits with TypeScript
|
|
79
|
+
├── Use v-bind shorthand (:prop) and v-on shorthand (@event)
|
|
80
|
+
└── No business logic in templates — compute in <script setup>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**GOOD**
|
|
84
|
+
```vue
|
|
85
|
+
<script setup lang="ts">
|
|
86
|
+
interface Props {
|
|
87
|
+
title: string;
|
|
88
|
+
variant?: 'primary' | 'secondary';
|
|
89
|
+
}
|
|
90
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
91
|
+
variant: 'primary',
|
|
92
|
+
});
|
|
93
|
+
const emit = defineEmits<{
|
|
94
|
+
(e: 'close'): void;
|
|
95
|
+
(e: 'submit', data: FormData): void;
|
|
96
|
+
}>();
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 4. Routing — Vue Router
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
MANDATORY:
|
|
106
|
+
├── Centralized route definitions in router/index.ts
|
|
107
|
+
├── Lazy load route components — () => import('./views/XxxView.vue')
|
|
108
|
+
├── Use named routes for navigation — NEVER hardcode paths in components
|
|
109
|
+
├── Navigation guards for auth in router.beforeEach — not in components
|
|
110
|
+
├── Type route params with defineProps or useRoute().params
|
|
111
|
+
└── Always have a catch-all 404 route: { path: '/:pathMatch(.*)*' }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 5. Template Rules
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
MANDATORY:
|
|
120
|
+
├── v-if over v-show for rarely toggled content (v-show for frequent toggles)
|
|
121
|
+
├── NEVER use v-if and v-for on the same element — wrap in <template v-if>
|
|
122
|
+
├── Use :key on all v-for — stable unique IDs, not array index
|
|
123
|
+
├── Emit events up, pass props down — NEVER mutate props
|
|
124
|
+
├── Use <slot> for composable component APIs — not excessive props
|
|
125
|
+
└── Use <Teleport> for modals/toasts — not DOM hacks
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**BAD** — v-if + v-for on same element:
|
|
129
|
+
```vue
|
|
130
|
+
<li v-for="user in users" v-if="user.active" :key="user.id">
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**GOOD**
|
|
134
|
+
```vue
|
|
135
|
+
<template v-for="user in users" :key="user.id">
|
|
136
|
+
<li v-if="user.active">{{ user.name }}</li>
|
|
137
|
+
</template>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Or better — use a computed:
|
|
141
|
+
```typescript
|
|
142
|
+
const activeUsers = computed(() => users.value.filter(u => u.active));
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 6. Composables (Custom Hooks)
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
MANDATORY:
|
|
151
|
+
├── Name: useXxx (useAuth, useUsers, useDebounce)
|
|
152
|
+
├── File location: composables/ directory
|
|
153
|
+
├── Return reactive refs and functions — consumers decide how to use them
|
|
154
|
+
├── Handle cleanup in onUnmounted — don't leak timers or listeners
|
|
155
|
+
└── One concern per composable
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 7. Anti-Patterns
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
NEVER:
|
|
164
|
+
├── Options API in new code (use Composition API + <script setup>)
|
|
165
|
+
├── Vuex in new code (use Pinia)
|
|
166
|
+
├── v-if + v-for on the same element
|
|
167
|
+
├── Mutating props — emit events instead
|
|
168
|
+
├── $refs for parent-child communication — use props/emits
|
|
169
|
+
├── Direct DOM manipulation (document.querySelector) — use template refs
|
|
170
|
+
├── Watchers for derived data — use computed()
|
|
171
|
+
├── console.log in committed code
|
|
172
|
+
└── this. in <script setup> — it doesn't exist
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Vue Verification Checklist
|
|
178
|
+
|
|
179
|
+
- [ ] Composition API with `<script setup>` — no Options API
|
|
180
|
+
- [ ] Pinia for global state — no Vuex
|
|
181
|
+
- [ ] VueQuery for server data (if applicable)
|
|
182
|
+
- [ ] Props defined with TypeScript interfaces via defineProps
|
|
183
|
+
- [ ] Emits defined with TypeScript via defineEmits
|
|
184
|
+
- [ ] Components under 150 lines
|
|
185
|
+
- [ ] Route components lazy loaded
|
|
186
|
+
- [ ] No v-if + v-for on same element
|
|
187
|
+
- [ ] Stable :key on all v-for — no array index
|
|
188
|
+
- [ ] Auth handled in router guards — not components
|
|
189
|
+
- [ ] No console.log in committed code
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Zustand Standards
|
|
2
|
+
|
|
3
|
+
These rules are MANDATORY. Violations fail the task. No exceptions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Store Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
MANDATORY:
|
|
11
|
+
├── One store per domain: useAuthStore, useCartStore, useUIStore
|
|
12
|
+
├── Zustand for CLIENT state only — use React Query for server data
|
|
13
|
+
├── Define store interface with TypeScript
|
|
14
|
+
├── Group related state and actions together
|
|
15
|
+
├── Export a single custom hook per store
|
|
16
|
+
└── NEVER create a single global store for everything
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**GOOD**
|
|
20
|
+
```typescript
|
|
21
|
+
interface AuthState {
|
|
22
|
+
user: User | null;
|
|
23
|
+
token: string | null;
|
|
24
|
+
isAuthenticated: boolean;
|
|
25
|
+
login: (credentials: LoginCredentials) => Promise<void>;
|
|
26
|
+
logout: () => void;
|
|
27
|
+
setUser: (user: User) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const useAuthStore = create<AuthState>()((set, get) => ({
|
|
31
|
+
user: null,
|
|
32
|
+
token: null,
|
|
33
|
+
isAuthenticated: false,
|
|
34
|
+
|
|
35
|
+
login: async (credentials) => {
|
|
36
|
+
const { user, token } = await authService.login(credentials);
|
|
37
|
+
set({ user, token, isAuthenticated: true });
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
logout: () => {
|
|
41
|
+
set({ user: null, token: null, isAuthenticated: false });
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
setUser: (user) => set({ user }),
|
|
45
|
+
}));
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 2. Selectors — Minimize Re-renders
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
MANDATORY:
|
|
54
|
+
├── Select only what the component needs — NEVER use the entire store
|
|
55
|
+
├── Use individual selectors for each piece of state
|
|
56
|
+
├── Create reusable selector hooks for common patterns
|
|
57
|
+
└── Use shallow equality for object selections
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**BAD** — triggers re-render on ANY store change:
|
|
61
|
+
```typescript
|
|
62
|
+
const store = useAuthStore();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**GOOD** — only re-renders when user changes:
|
|
66
|
+
```typescript
|
|
67
|
+
const user = useAuthStore((state) => state.user);
|
|
68
|
+
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
69
|
+
|
|
70
|
+
// For multiple values, use shallow:
|
|
71
|
+
import { useShallow } from 'zustand/react/shallow';
|
|
72
|
+
const { user, isAuthenticated } = useAuthStore(
|
|
73
|
+
useShallow((state) => ({ user: state.user, isAuthenticated: state.isAuthenticated }))
|
|
74
|
+
);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 3. Actions and Updates
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
MANDATORY:
|
|
83
|
+
├── Actions defined inside create() — not as external functions
|
|
84
|
+
├── Use set() for state updates — NEVER mutate state directly
|
|
85
|
+
├── Use get() to read current state inside actions
|
|
86
|
+
├── Async actions: handle loading/error inside the action
|
|
87
|
+
└── Partial updates: set() merges by default — only pass changed fields
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**GOOD**
|
|
91
|
+
```typescript
|
|
92
|
+
addItem: (item) => set((state) => ({
|
|
93
|
+
items: [...state.items, item],
|
|
94
|
+
total: state.total + item.price,
|
|
95
|
+
})),
|
|
96
|
+
|
|
97
|
+
removeItem: (itemId) => set((state) => ({
|
|
98
|
+
items: state.items.filter(i => i.id !== itemId),
|
|
99
|
+
})),
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 4. Middleware
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
WHEN NEEDED:
|
|
108
|
+
├── persist: for localStorage/sessionStorage persistence
|
|
109
|
+
├── devtools: for Redux DevTools integration (dev only)
|
|
110
|
+
├── immer: for mutable-style updates on complex nested state
|
|
111
|
+
├── Stack middleware with proper TypeScript: create<State>()(devtools(persist(...)))
|
|
112
|
+
└── Configure persist with a unique name and version for migration support
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**GOOD**
|
|
116
|
+
```typescript
|
|
117
|
+
export const useCartStore = create<CartState>()(
|
|
118
|
+
devtools(
|
|
119
|
+
persist(
|
|
120
|
+
(set, get) => ({
|
|
121
|
+
items: [],
|
|
122
|
+
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
|
|
123
|
+
clear: () => set({ items: [] }),
|
|
124
|
+
}),
|
|
125
|
+
{
|
|
126
|
+
name: 'cart-storage',
|
|
127
|
+
version: 1,
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
{ name: 'CartStore' }
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 5. Slices Pattern (Large Stores)
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
WHEN A STORE GROWS BEYOND 10 ACTIONS:
|
|
141
|
+
├── Split into slices — each slice manages a subset of state
|
|
142
|
+
├── Combine slices in a single create() call
|
|
143
|
+
├── Each slice has its own interface
|
|
144
|
+
└── Slices can read other slices via get()
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**GOOD**
|
|
148
|
+
```typescript
|
|
149
|
+
interface UserSlice {
|
|
150
|
+
user: User | null;
|
|
151
|
+
setUser: (user: User) => void;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
interface SettingsSlice {
|
|
155
|
+
theme: 'light' | 'dark';
|
|
156
|
+
toggleTheme: () => void;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const createUserSlice: StateCreator<UserSlice & SettingsSlice, [], [], UserSlice> = (set) => ({
|
|
160
|
+
user: null,
|
|
161
|
+
setUser: (user) => set({ user }),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const createSettingsSlice: StateCreator<UserSlice & SettingsSlice, [], [], SettingsSlice> = (set) => ({
|
|
165
|
+
theme: 'light',
|
|
166
|
+
toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
export const useAppStore = create<UserSlice & SettingsSlice>()((...args) => ({
|
|
170
|
+
...createUserSlice(...args),
|
|
171
|
+
...createSettingsSlice(...args),
|
|
172
|
+
}));
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 6. Anti-Patterns
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
NEVER:
|
|
181
|
+
├── Store server data in Zustand — use React Query
|
|
182
|
+
├── Use the entire store without selectors — causes unnecessary re-renders
|
|
183
|
+
├── One mega-store for the whole app — split by domain
|
|
184
|
+
├── Mutate state directly (state.items.push(x)) without immer middleware
|
|
185
|
+
├── Access store outside React without getState() (useStore.getState())
|
|
186
|
+
├── Derive state that could be computed — compute in selectors
|
|
187
|
+
└── console.log in store actions
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Zustand Verification Checklist
|
|
193
|
+
|
|
194
|
+
- [ ] One store per domain — no mega-stores
|
|
195
|
+
- [ ] Client state only — server data in React Query
|
|
196
|
+
- [ ] Typed with TypeScript interfaces
|
|
197
|
+
- [ ] Selectors used — no full-store subscriptions
|
|
198
|
+
- [ ] useShallow for multi-value selections
|
|
199
|
+
- [ ] Actions defined inside create()
|
|
200
|
+
- [ ] persist middleware configured with name and version
|
|
201
|
+
- [ ] devtools enabled in development
|
|
202
|
+
- [ ] No direct state mutation without immer
|
|
203
|
+
- [ ] No console.log in store code
|