@tekyzinc/gsd-t 2.46.11 → 2.50.11
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 +64 -1
- package/commands/gsd-t-execute.md +79 -3
- package/commands/gsd-t-help.md +18 -2
- package/commands/gsd-t-init.md +7 -0
- package/commands/gsd-t-integrate.md +16 -0
- package/commands/gsd-t-quick.md +56 -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,225 @@
|
|
|
1
|
+
# PostgreSQL Standards
|
|
2
|
+
|
|
3
|
+
These rules are MANDATORY. Violations fail the task. No exceptions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Naming Conventions
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
MANDATORY:
|
|
11
|
+
├── Tables: snake_case, plural (users, order_items)
|
|
12
|
+
├── Columns: snake_case, singular (first_name, created_at)
|
|
13
|
+
├── Primary keys: id (UUID preferred over serial for distributed systems)
|
|
14
|
+
├── Foreign keys: {referenced_table_singular}_id (user_id, order_id)
|
|
15
|
+
├── Indexes: idx_{table}_{columns} (idx_users_email)
|
|
16
|
+
├── Constraints: {type}_{table}_{columns} (uq_users_email, fk_orders_user_id)
|
|
17
|
+
├── Enums: snake_case singular (user_role, order_status)
|
|
18
|
+
└── Boolean columns: is_ or has_ prefix (is_active, has_verified_email)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 2. Schema Design
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
MANDATORY:
|
|
27
|
+
├── Every table has: id (PK), created_at (timestamptz DEFAULT now()), updated_at
|
|
28
|
+
├── Use timestamptz — NEVER timestamp without time zone
|
|
29
|
+
├── Use UUID for primary keys in distributed or API-exposed systems
|
|
30
|
+
├── Use appropriate types: text (not varchar), numeric (not float for money)
|
|
31
|
+
├── Add NOT NULL constraints by default — allow NULL only with explicit reason
|
|
32
|
+
├── Foreign keys with ON DELETE policy (CASCADE, SET NULL, or RESTRICT — choose deliberately)
|
|
33
|
+
└── NEVER store JSON when a proper relational schema exists — use jsonb only for truly unstructured data
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**GOOD**
|
|
37
|
+
```sql
|
|
38
|
+
CREATE TABLE users (
|
|
39
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
40
|
+
email TEXT NOT NULL,
|
|
41
|
+
display_name TEXT NOT NULL,
|
|
42
|
+
role user_role NOT NULL DEFAULT 'viewer',
|
|
43
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
44
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
45
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
46
|
+
CONSTRAINT uq_users_email UNIQUE (email)
|
|
47
|
+
);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 3. Migrations
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
MANDATORY:
|
|
56
|
+
├── One migration per change — never combine unrelated schema changes
|
|
57
|
+
├── Migrations are forward-only in production — NEVER edit a deployed migration
|
|
58
|
+
├── Name format: {timestamp}_{description}.sql (20260325_add_users_table.sql)
|
|
59
|
+
├── Every migration must be reversible — include a down/rollback section
|
|
60
|
+
├── Test migrations on a copy of production data before deploying
|
|
61
|
+
└── NEVER use DROP COLUMN or DROP TABLE without user approval (Destructive Action Guard)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 4. Indexing
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
MANDATORY:
|
|
70
|
+
├── Index every foreign key column
|
|
71
|
+
├── Index columns used in WHERE, JOIN, and ORDER BY
|
|
72
|
+
├── Use partial indexes for common filter patterns: WHERE is_active = true
|
|
73
|
+
├── Use composite indexes in query column order (leftmost prefix rule)
|
|
74
|
+
├── GIN indexes for jsonb, array, and full-text search columns
|
|
75
|
+
├── NEVER create indexes speculatively — profile queries first (EXPLAIN ANALYZE)
|
|
76
|
+
└── Monitor unused indexes and remove them
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**GOOD**
|
|
80
|
+
```sql
|
|
81
|
+
-- Foreign key index
|
|
82
|
+
CREATE INDEX idx_orders_user_id ON orders (user_id);
|
|
83
|
+
|
|
84
|
+
-- Composite for common query pattern
|
|
85
|
+
CREATE INDEX idx_orders_user_status ON orders (user_id, status);
|
|
86
|
+
|
|
87
|
+
-- Partial index — only active users
|
|
88
|
+
CREATE INDEX idx_users_active_email ON users (email) WHERE is_active = true;
|
|
89
|
+
|
|
90
|
+
-- GIN for jsonb queries
|
|
91
|
+
CREATE INDEX idx_products_metadata ON products USING GIN (metadata);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 5. Query Patterns
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
MANDATORY:
|
|
100
|
+
├── Use parameterized queries — NEVER string concatenation for SQL
|
|
101
|
+
├── SELECT only the columns you need — NEVER SELECT *
|
|
102
|
+
├── Use LIMIT on all user-facing queries — prevent unbounded result sets
|
|
103
|
+
├── Use EXISTS instead of COUNT(*) > 0 for existence checks
|
|
104
|
+
├── Use CTEs (WITH) for readability — but not for performance (CTEs can be optimization fences)
|
|
105
|
+
├── Prefer JOIN over subquery where equivalent
|
|
106
|
+
└── Always include ORDER BY when results must be deterministic
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**BAD**
|
|
110
|
+
```sql
|
|
111
|
+
SELECT * FROM users WHERE name LIKE '%' || $1 || '%';
|
|
112
|
+
SELECT COUNT(*) FROM orders WHERE user_id = $1; -- just to check existence
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**GOOD**
|
|
116
|
+
```sql
|
|
117
|
+
SELECT id, email, display_name FROM users WHERE name ILIKE '%' || $1 || '%' LIMIT 50;
|
|
118
|
+
SELECT EXISTS(SELECT 1 FROM orders WHERE user_id = $1);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 6. Connection Management
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
MANDATORY:
|
|
127
|
+
├── Use connection pooling (PgBouncer, or built-in pool in your ORM/driver)
|
|
128
|
+
├── Set pool size based on workload — not unlimited
|
|
129
|
+
├── Close/release connections after use — never leak
|
|
130
|
+
├── Set statement_timeout on application connections (e.g., 30s)
|
|
131
|
+
├── Use read replicas for heavy read workloads
|
|
132
|
+
└── Serverless: use Supabase connection pooler or PgBouncer — not direct connections
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 7. Transactions
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
MANDATORY:
|
|
141
|
+
├── Wrap multi-statement operations in transactions
|
|
142
|
+
├── Keep transactions short — don't hold locks while doing I/O
|
|
143
|
+
├── Use appropriate isolation level (READ COMMITTED is default — sufficient for most cases)
|
|
144
|
+
├── Handle deadlocks with retry logic (up to 3 retries)
|
|
145
|
+
└── NEVER leave transactions open — always COMMIT or ROLLBACK
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 8. Graph-in-SQL Patterns
|
|
151
|
+
|
|
152
|
+
When implementing graph structures in PostgreSQL (adjacency lists, knowledge graphs, hierarchies):
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
PATTERNS:
|
|
156
|
+
├── Node tables: one table per entity type with UUID primary keys
|
|
157
|
+
├── Edge tables (junction): {source}_id + {target}_id + metadata columns
|
|
158
|
+
│ Add relevance_score, weight, or edge_count for weighted graphs
|
|
159
|
+
├── Hierarchies: parent_id self-referencing FK + recursive CTE for traversal
|
|
160
|
+
├── Index both sides of every edge table FK
|
|
161
|
+
├── Stable seed UUIDs for reproducible deploys (deterministic UUID format)
|
|
162
|
+
└── In-memory cache (LRU, 5-min TTL) for frequently traversed paths
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Hierarchy traversal — recursive CTE:**
|
|
166
|
+
```sql
|
|
167
|
+
WITH RECURSIVE ancestors AS (
|
|
168
|
+
SELECT id, name, parent_id, 0 AS depth
|
|
169
|
+
FROM graph_business_types
|
|
170
|
+
WHERE id = $1
|
|
171
|
+
UNION ALL
|
|
172
|
+
SELECT t.id, t.name, t.parent_id, a.depth + 1
|
|
173
|
+
FROM graph_business_types t
|
|
174
|
+
JOIN ancestors a ON t.id = a.parent_id
|
|
175
|
+
)
|
|
176
|
+
SELECT * FROM ancestors ORDER BY depth;
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Weighted edge query:**
|
|
180
|
+
```sql
|
|
181
|
+
SELECT w.id, w.name, e.relevance_score
|
|
182
|
+
FROM graph_edges_bt_workflow e
|
|
183
|
+
JOIN graph_workflows w ON w.id = e.workflow_id
|
|
184
|
+
WHERE e.business_type_id = $1
|
|
185
|
+
ORDER BY e.relevance_score DESC
|
|
186
|
+
LIMIT 8;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Rules:**
|
|
190
|
+
- Index edge tables on both FK columns
|
|
191
|
+
- Use ON DELETE CASCADE for edges when the node is deleted
|
|
192
|
+
- Consider materialized views for expensive multi-hop traversals
|
|
193
|
+
- For deep graphs (5+ hops), evaluate whether Neo4j is more appropriate
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 9. Anti-Patterns
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
NEVER:
|
|
201
|
+
├── SELECT * in application queries
|
|
202
|
+
├── String concatenation for SQL — parameterized queries only
|
|
203
|
+
├── Unbounded queries without LIMIT
|
|
204
|
+
├── timestamp without time zone — always timestamptz
|
|
205
|
+
├── float/double for money — use numeric or integer (cents)
|
|
206
|
+
├── Storing structured relational data in jsonb
|
|
207
|
+
├── Missing indexes on foreign keys
|
|
208
|
+
├── Long-running transactions holding locks
|
|
209
|
+
└── Direct connections from serverless without pooling
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## PostgreSQL Verification Checklist
|
|
215
|
+
|
|
216
|
+
- [ ] Naming follows conventions (snake_case, plural tables, singular columns)
|
|
217
|
+
- [ ] Every table has id, created_at, updated_at
|
|
218
|
+
- [ ] timestamptz used — not timestamp
|
|
219
|
+
- [ ] All foreign keys indexed
|
|
220
|
+
- [ ] Parameterized queries only — no string concatenation
|
|
221
|
+
- [ ] All user-facing queries have LIMIT
|
|
222
|
+
- [ ] Connection pooling configured
|
|
223
|
+
- [ ] Migrations are forward-only and reversible
|
|
224
|
+
- [ ] No SELECT * in application code
|
|
225
|
+
- [ ] Graph edges indexed on both FK columns (if applicable)
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Python Standards
|
|
2
|
+
|
|
3
|
+
These rules are MANDATORY. Violations fail the task. No exceptions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Type Hints
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
MANDATORY:
|
|
11
|
+
├── Type hints on ALL function signatures (params + return)
|
|
12
|
+
├── Use built-in generics (list, dict, tuple) — not typing.List etc. (Python 3.9+)
|
|
13
|
+
├── Use | for unions — not typing.Union (Python 3.10+)
|
|
14
|
+
├── Use dataclasses or Pydantic models for structured data — NEVER raw dicts
|
|
15
|
+
└── Run mypy or pyright in CI — no untyped public functions
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**BAD**
|
|
19
|
+
```python
|
|
20
|
+
def get_users(filters):
|
|
21
|
+
result = {"users": [], "total": 0}
|
|
22
|
+
return result
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**GOOD**
|
|
26
|
+
```python
|
|
27
|
+
@dataclass
|
|
28
|
+
class UserList:
|
|
29
|
+
users: list[User]
|
|
30
|
+
total: int
|
|
31
|
+
|
|
32
|
+
def get_users(filters: UserFilters) -> UserList:
|
|
33
|
+
...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 2. Project Structure
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
MANDATORY:
|
|
42
|
+
├── Use src/ layout for packages — src/{package_name}/
|
|
43
|
+
├── Tests mirror source: tests/{module}/test_{file}.py
|
|
44
|
+
├── One class per file for major classes — small helpers can share
|
|
45
|
+
├── __init__.py exports only the public API
|
|
46
|
+
└── Config in environment variables or .env — NEVER hardcoded
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 3. Data Models
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
MANDATORY:
|
|
55
|
+
├── Use dataclasses for internal data structures
|
|
56
|
+
├── Use Pydantic BaseModel for API input/output and validation
|
|
57
|
+
├── Use Enums for fixed option sets — NEVER magic strings
|
|
58
|
+
├── Frozen dataclasses for immutable value objects
|
|
59
|
+
└── NEVER pass raw dicts between functions — define a model
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**BAD** — `def create_user(data: dict) -> dict:`
|
|
63
|
+
|
|
64
|
+
**GOOD**
|
|
65
|
+
```python
|
|
66
|
+
class CreateUserRequest(BaseModel):
|
|
67
|
+
name: str = Field(min_length=2)
|
|
68
|
+
email: EmailStr
|
|
69
|
+
role: UserRole # Enum
|
|
70
|
+
|
|
71
|
+
class UserResponse(BaseModel):
|
|
72
|
+
id: str
|
|
73
|
+
name: str
|
|
74
|
+
email: str
|
|
75
|
+
role: UserRole
|
|
76
|
+
created_at: datetime
|
|
77
|
+
|
|
78
|
+
def create_user(request: CreateUserRequest) -> UserResponse:
|
|
79
|
+
...
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 4. Error Handling
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
MANDATORY:
|
|
88
|
+
├── Define custom exception hierarchy per domain — NEVER raise bare Exception
|
|
89
|
+
├── Catch specific exceptions — NEVER bare except: or except Exception:
|
|
90
|
+
├── Use try/except at boundaries (API handlers, CLI entry) — not deep in logic
|
|
91
|
+
├── Log exceptions with context (structlog or logging) before re-raising
|
|
92
|
+
└── Return error types or raise — NEVER return None to signal failure
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**BAD**
|
|
96
|
+
```python
|
|
97
|
+
try:
|
|
98
|
+
result = do_something()
|
|
99
|
+
except:
|
|
100
|
+
return None
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**GOOD**
|
|
104
|
+
```python
|
|
105
|
+
class UserNotFoundError(DomainError):
|
|
106
|
+
def __init__(self, user_id: str):
|
|
107
|
+
super().__init__(f"User {user_id} not found")
|
|
108
|
+
self.user_id = user_id
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
user = user_repo.get(user_id)
|
|
112
|
+
except UserNotFoundError:
|
|
113
|
+
logger.warning("user_not_found", user_id=user_id)
|
|
114
|
+
raise
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 5. Functions and Methods
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
MANDATORY:
|
|
123
|
+
├── Max 30 lines per function — split if longer
|
|
124
|
+
├── Max 200 lines per file — create new modules if needed
|
|
125
|
+
├── Single responsibility — one function does one thing
|
|
126
|
+
├── Use keyword arguments for functions with 3+ parameters
|
|
127
|
+
├── Default mutable arguments are FORBIDDEN — use None + factory
|
|
128
|
+
└── Docstrings on public functions only — skip for obvious private methods
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**BAD** — `def register(name, email, role, send_email=True, template=[], notify=[]):`
|
|
132
|
+
|
|
133
|
+
**GOOD**
|
|
134
|
+
```python
|
|
135
|
+
def register(
|
|
136
|
+
*,
|
|
137
|
+
name: str,
|
|
138
|
+
email: str,
|
|
139
|
+
role: UserRole,
|
|
140
|
+
send_email: bool = True,
|
|
141
|
+
template: list[str] | None = None,
|
|
142
|
+
notify: list[str] | None = None,
|
|
143
|
+
) -> User:
|
|
144
|
+
template = template or []
|
|
145
|
+
notify = notify or []
|
|
146
|
+
...
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 6. Async Patterns
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
WHEN USING ASYNC:
|
|
155
|
+
├── async def for I/O-bound operations (HTTP, DB, file) — not CPU-bound
|
|
156
|
+
├── Use asyncio.gather for concurrent I/O — not sequential awaits
|
|
157
|
+
├── NEVER mix sync and async — use run_in_executor for sync libraries
|
|
158
|
+
├── Always set timeouts on external calls (httpx, aiohttp)
|
|
159
|
+
└── Use async context managers for connections and sessions
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**BAD** — sequential awaits for independent calls:
|
|
163
|
+
```python
|
|
164
|
+
users = await get_users()
|
|
165
|
+
orders = await get_orders() # waits for users to finish first
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**GOOD**
|
|
169
|
+
```python
|
|
170
|
+
users, orders = await asyncio.gather(get_users(), get_orders())
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 7. Testing
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
MANDATORY:
|
|
179
|
+
├── pytest as the test runner — not unittest
|
|
180
|
+
├── Use fixtures for setup/teardown — not setUp/tearDown methods
|
|
181
|
+
├── Use parametrize for testing multiple inputs
|
|
182
|
+
├── Test file naming: test_{module}.py
|
|
183
|
+
├── Test function naming: test_{behavior}_when_{condition}
|
|
184
|
+
└── Assert with plain assert — not self.assertEqual
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**GOOD**
|
|
188
|
+
```python
|
|
189
|
+
@pytest.fixture
|
|
190
|
+
def user_service(db_session: Session) -> UserService:
|
|
191
|
+
return UserService(db_session)
|
|
192
|
+
|
|
193
|
+
@pytest.mark.parametrize("role,expected", [
|
|
194
|
+
(UserRole.ADMIN, True),
|
|
195
|
+
(UserRole.VIEWER, False),
|
|
196
|
+
])
|
|
197
|
+
def test_can_delete_when_role(user_service: UserService, role: UserRole, expected: bool):
|
|
198
|
+
assert user_service.can_delete(role) == expected
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 8. Dependencies and Imports
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
MANDATORY:
|
|
207
|
+
├── Use virtual environments (venv, poetry, uv) — NEVER install globally
|
|
208
|
+
├── Pin dependencies in requirements.txt or pyproject.toml
|
|
209
|
+
├── Import order: stdlib → third-party → local (enforced by isort/ruff)
|
|
210
|
+
├── Use absolute imports for cross-module — relative for same-package
|
|
211
|
+
└── NEVER import * — explicit imports only
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 9. Anti-Patterns
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
NEVER:
|
|
220
|
+
├── Bare except: or except Exception: without re-raise
|
|
221
|
+
├── Mutable default arguments (def f(items=[]))
|
|
222
|
+
├── Global mutable state — use dependency injection
|
|
223
|
+
├── String concatenation for SQL — use parameterized queries
|
|
224
|
+
├── print() for logging — use logging/structlog
|
|
225
|
+
├── Raw dicts as function params or return types
|
|
226
|
+
├── Nested functions deeper than 2 levels
|
|
227
|
+
└── Type: ignore without explanation comment
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Python Verification Checklist
|
|
233
|
+
|
|
234
|
+
- [ ] Type hints on all function signatures
|
|
235
|
+
- [ ] Pydantic or dataclass for all structured data — no raw dicts
|
|
236
|
+
- [ ] Custom exceptions — no bare Exception raises
|
|
237
|
+
- [ ] Functions under 30 lines, files under 200 lines
|
|
238
|
+
- [ ] No mutable default arguments
|
|
239
|
+
- [ ] pytest with fixtures — no unittest patterns
|
|
240
|
+
- [ ] Import order enforced (stdlib → third-party → local)
|
|
241
|
+
- [ ] No print() in committed code — use logging
|
|
242
|
+
- [ ] Virtual environment with pinned dependencies
|
|
243
|
+
- [ ] No string-formatted SQL — parameterized queries only
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# React Native Standards
|
|
2
|
+
|
|
3
|
+
These rules are MANDATORY. Violations fail the task. No exceptions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. State Management — React Query + Zustand
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
MANDATORY:
|
|
11
|
+
├── React Query (TanStack Query) for ALL server data — NEVER useEffect + fetch
|
|
12
|
+
├── Zustand for client-side global state (auth, theme, navigation state)
|
|
13
|
+
├── useState for local UI state only (toggles, form inputs)
|
|
14
|
+
├── NEVER store server data in useState or Zustand — it belongs in the query cache
|
|
15
|
+
└── Set staleTime explicitly on all queries
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**GOOD**
|
|
19
|
+
```tsx
|
|
20
|
+
// Server data → React Query
|
|
21
|
+
const { data: users } = useQuery({
|
|
22
|
+
queryKey: ['users'],
|
|
23
|
+
queryFn: api.getUsers,
|
|
24
|
+
staleTime: 5 * 60 * 1000,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Client state → Zustand
|
|
28
|
+
const useAuthStore = create<AuthState>((set) => ({
|
|
29
|
+
token: null,
|
|
30
|
+
setToken: (token) => set({ token }),
|
|
31
|
+
logout: () => set({ token: null }),
|
|
32
|
+
}));
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 2. Component Design
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
MANDATORY:
|
|
41
|
+
├── Max 150 lines per component — extract sub-components
|
|
42
|
+
├── Use FlatList for all dynamic lists — NEVER ScrollView with .map()
|
|
43
|
+
├── Separate screen components (screens/) from reusable components (components/)
|
|
44
|
+
├── One component per file
|
|
45
|
+
├── No business logic in JSX — compute above the return
|
|
46
|
+
└── Use custom hooks for complex logic (useXxx)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**BAD**
|
|
50
|
+
```tsx
|
|
51
|
+
<ScrollView>
|
|
52
|
+
{items.map(item => <ItemRow key={item.id} item={item} />)}
|
|
53
|
+
</ScrollView>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**GOOD**
|
|
57
|
+
```tsx
|
|
58
|
+
<FlatList
|
|
59
|
+
data={items}
|
|
60
|
+
keyExtractor={(item) => item.id}
|
|
61
|
+
renderItem={({ item }) => <ItemRow item={item} />}
|
|
62
|
+
ListEmptyComponent={<EmptyState />}
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 3. Navigation — React Navigation
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
MANDATORY:
|
|
72
|
+
├── Use React Navigation (not react-native-router-flux, not expo-router for bare RN)
|
|
73
|
+
├── Type all navigation params with RootStackParamList
|
|
74
|
+
├── Define all routes in a central navigation config
|
|
75
|
+
├── Deep linking config in the navigator — not hardcoded in components
|
|
76
|
+
└── Handle auth flow with conditional navigator (logged in → app, else → auth)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**GOOD**
|
|
80
|
+
```tsx
|
|
81
|
+
type RootStackParamList = {
|
|
82
|
+
Home: undefined;
|
|
83
|
+
UserDetail: { userId: string };
|
|
84
|
+
Settings: undefined;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const Stack = createNativeStackNavigator<RootStackParamList>();
|
|
88
|
+
|
|
89
|
+
function AppNavigator() {
|
|
90
|
+
const { isLoggedIn } = useAuth();
|
|
91
|
+
return (
|
|
92
|
+
<Stack.Navigator>
|
|
93
|
+
{isLoggedIn ? (
|
|
94
|
+
<>
|
|
95
|
+
<Stack.Screen name="Home" component={HomeScreen} />
|
|
96
|
+
<Stack.Screen name="UserDetail" component={UserDetailScreen} />
|
|
97
|
+
</>
|
|
98
|
+
) : (
|
|
99
|
+
<Stack.Screen name="Login" component={LoginScreen} />
|
|
100
|
+
)}
|
|
101
|
+
</Stack.Navigator>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 4. Styling
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
MANDATORY:
|
|
112
|
+
├── Use StyleSheet.create for all styles — NEVER inline style objects
|
|
113
|
+
├── Co-locate styles at the bottom of the component file
|
|
114
|
+
├── Use a theme object for colors, spacing, typography — NEVER hardcode
|
|
115
|
+
├── Responsive: use useWindowDimensions or percentage-based layouts
|
|
116
|
+
└── Platform-specific styles via Platform.select or .ios.tsx/.android.tsx files
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**BAD** — `<View style={{ padding: 16, backgroundColor: '#f5f5f5' }}>`
|
|
120
|
+
|
|
121
|
+
**GOOD**
|
|
122
|
+
```tsx
|
|
123
|
+
const styles = StyleSheet.create({
|
|
124
|
+
container: {
|
|
125
|
+
padding: theme.spacing.md,
|
|
126
|
+
backgroundColor: theme.colors.surface,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 5. Performance
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
MANDATORY:
|
|
137
|
+
├── FlatList with keyExtractor — NEVER ScrollView for lists
|
|
138
|
+
├── Use React.memo on list item components
|
|
139
|
+
├── useCallback for renderItem and event handlers passed to FlatList
|
|
140
|
+
├── Avoid anonymous functions in props of list items
|
|
141
|
+
├── Use react-native-fast-image for image caching
|
|
142
|
+
├── Minimize bridge calls — batch state updates
|
|
143
|
+
└── Profile with Flipper or React DevTools before optimizing
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 6. Platform Differences
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
MANDATORY:
|
|
152
|
+
├── Test on BOTH iOS and Android before marking complete
|
|
153
|
+
├── Use Platform.OS checks sparingly — prefer cross-platform components
|
|
154
|
+
├── Handle safe areas with SafeAreaView or useSafeAreaInsets
|
|
155
|
+
├── Handle keyboard: KeyboardAvoidingView (behavior differs per platform)
|
|
156
|
+
├── Permissions: request at point of use, explain why, handle denial gracefully
|
|
157
|
+
└── Status bar: manage with StatusBar component — don't assume default
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 7. Offline and Networking
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
WHEN APPLICABLE:
|
|
166
|
+
├── React Query's built-in cache for offline reads
|
|
167
|
+
├── Use @react-native-community/netinfo for connectivity detection
|
|
168
|
+
├── Show offline indicator — don't silently fail
|
|
169
|
+
├── Queue mutations when offline, replay when online
|
|
170
|
+
└── Set reasonable timeouts on all network requests
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 8. Error Handling
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
MANDATORY:
|
|
179
|
+
├── Global error boundary at the app root — never a blank crash screen
|
|
180
|
+
├── Per-screen error boundaries for isolated failures
|
|
181
|
+
├── Handle loading, error, and empty states for every data fetch
|
|
182
|
+
├── Crash reporting (Sentry, Bugsnag) in production builds
|
|
183
|
+
└── User-friendly error messages — not raw error strings
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 9. Anti-Patterns
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
NEVER:
|
|
192
|
+
├── ScrollView with .map() for dynamic lists (use FlatList)
|
|
193
|
+
├── Inline style objects (use StyleSheet.create)
|
|
194
|
+
├── useEffect for data fetching (use React Query)
|
|
195
|
+
├── Hardcoded colors/spacing — use theme
|
|
196
|
+
├── console.log in committed code
|
|
197
|
+
├── Ignoring platform differences — test on both
|
|
198
|
+
├── Ignoring keyboard avoidance — forms become unusable
|
|
199
|
+
└── Large images without caching — use FastImage
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## React Native Verification Checklist
|
|
205
|
+
|
|
206
|
+
- [ ] React Query for server data — no useEffect + fetch
|
|
207
|
+
- [ ] FlatList for all dynamic lists — no ScrollView + map
|
|
208
|
+
- [ ] Components under 150 lines
|
|
209
|
+
- [ ] StyleSheet.create for all styles — no inline objects
|
|
210
|
+
- [ ] Theme object for colors/spacing — no hardcoded values
|
|
211
|
+
- [ ] React Navigation with typed params
|
|
212
|
+
- [ ] Loading, error, and empty states handled
|
|
213
|
+
- [ ] Tested on both iOS and Android
|
|
214
|
+
- [ ] Safe areas and keyboard avoidance handled
|
|
215
|
+
- [ ] No console.log in committed code
|
|
216
|
+
- [ ] Error boundaries at root and per-screen
|