everything-gemini 1.2.0 → 1.8.0
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/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- package/.github/ISSUE_TEMPLATE/subagent_proposal.md +29 -0
- package/.github/workflows/ci.yml +72 -1
- package/.github/workflows/release.yml +17 -2
- package/CHANGELOG.md +155 -0
- package/CONTRIBUTING.md +85 -4
- package/README.md +134 -19
- package/action.yml +35 -0
- package/agents/browser-qa.md +1 -1
- package/agents/database-migrator.md +26 -0
- package/agents/documentation-writer.md +27 -0
- package/agents/incident-responder.md +34 -0
- package/agents/performance-tuner.md +27 -0
- package/agents/release-engineer.md +34 -0
- package/bin/everything-gemini +1517 -122
- package/docs/COMMUNITY_SUBMISSIONS.md +88 -0
- package/docs/LAUNCH_KIT.md +138 -13
- package/docs/architecture/progressive-disclosure.md +3 -3
- package/docs/index.html +401 -40
- package/docs/launch-kit.md +163 -0
- package/examples/cli-workflows/demo_workflow.sh +15 -7
- package/examples/python-sdk/README.md +28 -5
- package/examples/python-sdk/documentation_audit_pipeline.py +83 -0
- package/examples/python-sdk/incident_triage_pipeline.py +170 -0
- package/examples/python-sdk/multi_agent_pipeline.py +95 -0
- package/examples/python-sdk/release_readiness_audit.py +144 -0
- package/hooks/secret-scrubber/hooks.json +16 -0
- package/hooks/secret-scrubber/scripts/scrub-secrets.sh +62 -0
- package/mcp/README.md +20 -0
- package/mcp/mcp_config.example.json +35 -0
- package/package.json +3 -1
- package/plugins/core/rules/core-practices.md +63 -4
- package/plugins/python-ai/rules/ai-agent-patterns.md +67 -4
- package/plugins/security-shield/rules/zero-trust.md +60 -4
- package/plugins/web-fullstack/rules/frontend-standards.md +74 -4
- package/rules/paradigms/security-hardened.md +53 -10
- package/rules/paradigms/tdd.md +65 -8
- package/scripts/install.ps1 +14 -0
- package/scripts/install.sh +15 -1
- package/scripts/validate.sh +103 -12
- package/skills/apache-kafka-streams/SKILL.md +152 -0
- package/skills/argo-workflows/SKILL.md +151 -0
- package/skills/axum-web-service/SKILL.md +159 -0
- package/skills/cilium-ebpf-networking/SKILL.md +145 -0
- package/skills/clickhouse-analytics/SKILL.md +128 -0
- package/skills/dbt-transformation/SKILL.md +179 -0
- package/skills/debezium-cdc/SKILL.md +166 -0
- package/skills/duckdb-local-olap/SKILL.md +134 -0
- package/skills/fastapi-production/SKILL.md +157 -0
- package/skills/grpc-connect-rpc/SKILL.md +176 -0
- package/skills/langgraph-orchestrator/SKILL.md +144 -0
- package/skills/litellm-proxy-gateway/SKILL.md +154 -0
- package/skills/nats-jetstream/SKILL.md +122 -0
- package/skills/open-telemetry-tracing/SKILL.md +151 -0
- package/skills/playwright-visual-regression/SKILL.md +124 -0
- package/skills/redis-cache-patterns/SKILL.md +159 -0
- package/skills/svelte-kit-architect/SKILL.md +190 -0
- package/skills/temporal-workflows/SKILL.md +158 -0
- package/skills/trpc-react-query/SKILL.md +169 -0
- package/skills/turborepo-monorepo/SKILL.md +199 -0
- package/skills/vllm-inference/SKILL.md +144 -0
- package/skills/wasm-rust-optimizer/SKILL.md +130 -0
- package/templates/full-power/hooks.json +14 -0
- package/templates/full-power/mcp_config.json +43 -0
- package/templates/recommended/hooks.json +14 -0
- package/tests/cli.test.js +383 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debezium-cdc
|
|
3
|
+
description: >-
|
|
4
|
+
Change Data Capture (CDC) streaming architectures using Debezium, PostgreSQL logical decoding (pgoutput), MySQL binlog replication, Kafka Connect, and transactional outbox patterns. Use when capturing real-time database mutations, synchronizing search indices, or avoiding dual-write race conditions.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Debezium Change Data Capture (CDC) Architecture
|
|
8
|
+
|
|
9
|
+
A production runbook for implementing distributed **Change Data Capture (CDC)** pipelines using Debezium, PostgreSQL/MySQL WAL replication, Kafka Connect, and event-driven data streaming.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🎯 Core Architectural Principles
|
|
14
|
+
|
|
15
|
+
1. **Log-Based CDC Over Polling**: Reads write-ahead logs (WAL / binlog) directly at the storage engine level, incurring minimal CPU overhead and zero query locks on primary tables.
|
|
16
|
+
2. **Transactional Outbox Pattern**: Guarantees atomic database operations and event emission within a single ACID transaction without two-phase commit (2PC) or dual-write inconsistencies.
|
|
17
|
+
3. **Strict Ordering Guarantees**: Partitioning by primary key ensures sequential ordering per record entity across consumer groups.
|
|
18
|
+
4. **Idempotent Consumers**: Design downstream event processors with upsert semantics and revision monotonic version checks.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🏗️ Debezium PostgreSQL Connector Configuration
|
|
23
|
+
|
|
24
|
+
### 1. Database Prerequisite (`postgresql.conf`)
|
|
25
|
+
|
|
26
|
+
```ini
|
|
27
|
+
# Enable logical replication
|
|
28
|
+
wal_level = logical
|
|
29
|
+
max_wal_senders = 10
|
|
30
|
+
max_replication_slots = 10
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Kafka Connect Connector Payload (`debezium-postgres.json`)
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"name": "postgres-order-cdc",
|
|
38
|
+
"config": {
|
|
39
|
+
"connector.class": "io.debezium.connector.postgresql.PostgresConnector",
|
|
40
|
+
"tasks.max": "1",
|
|
41
|
+
"plugin.name": "pgoutput",
|
|
42
|
+
"database.hostname": "postgres.internal",
|
|
43
|
+
"database.port": "5432",
|
|
44
|
+
"database.user": "debezium_cdc",
|
|
45
|
+
"database.password": "${file:/secrets/db-credentials.properties:password}",
|
|
46
|
+
"database.dbname": "production_app",
|
|
47
|
+
"database.server.name": "prod_cdc",
|
|
48
|
+
"table.include.list": "public.orders,public.outbox_events",
|
|
49
|
+
"slot.name": "debezium_orders_slot",
|
|
50
|
+
"publication.name": "dbz_orders_pub",
|
|
51
|
+
"publication.autocreate.mode": "filtered",
|
|
52
|
+
"decimal.handling.mode": "double",
|
|
53
|
+
"tombstones.on.delete": "true",
|
|
54
|
+
"heartbeat.interval.ms": "5000"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Deploy to Kafka Connect cluster via REST API:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
curl -i -X POST -H "Accept:application/json" -H "Content-Type:application/json" \
|
|
63
|
+
http://kafka-connect.internal:8083/connectors/ \
|
|
64
|
+
-d @debezium-postgres.json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 📦 Transactional Outbox Pattern Implementation
|
|
70
|
+
|
|
71
|
+
### Step 1: Outbox Event Table Schema
|
|
72
|
+
|
|
73
|
+
```sql
|
|
74
|
+
CREATE TABLE outbox_events (
|
|
75
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
76
|
+
aggregate_type VARCHAR(64) NOT NULL,
|
|
77
|
+
aggregate_id VARCHAR(64) NOT NULL,
|
|
78
|
+
event_type VARCHAR(64) NOT NULL,
|
|
79
|
+
payload JSONB NOT NULL,
|
|
80
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
-- Index for optional periodic cleanup
|
|
84
|
+
CREATE INDEX idx_outbox_created_at ON outbox_events (created_at);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Step 2: Atomic Business Transaction (TypeScript / Node.js)
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { PoolClient } from 'pg';
|
|
91
|
+
|
|
92
|
+
interface OrderEvent {
|
|
93
|
+
orderId: string;
|
|
94
|
+
userId: string;
|
|
95
|
+
totalCents: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function createOrderWithOutbox(client: PoolClient, event: OrderEvent): Promise<void> {
|
|
99
|
+
try {
|
|
100
|
+
await client.query('BEGIN');
|
|
101
|
+
|
|
102
|
+
// 1. Mutate primary business state
|
|
103
|
+
const orderSql = `
|
|
104
|
+
INSERT INTO orders (id, user_id, total_cents, status)
|
|
105
|
+
VALUES ($1, $2, $3, 'CREATED')
|
|
106
|
+
`;
|
|
107
|
+
await client.query(orderSql, [event.orderId, event.userId, event.totalCents]);
|
|
108
|
+
|
|
109
|
+
// 2. Append event to outbox within same transaction
|
|
110
|
+
const outboxSql = `
|
|
111
|
+
INSERT INTO outbox_events (aggregate_type, aggregate_id, event_type, payload)
|
|
112
|
+
VALUES ('Order', $1, 'OrderCreated', $2)
|
|
113
|
+
`;
|
|
114
|
+
await client.query(outboxSql, [event.orderId, JSON.stringify(event)]);
|
|
115
|
+
|
|
116
|
+
await client.query('COMMIT');
|
|
117
|
+
} catch (error) {
|
|
118
|
+
await client.query('ROLLBACK');
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 🔄 Debezium Event Payload Structure
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"before": null,
|
|
131
|
+
"after": {
|
|
132
|
+
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
133
|
+
"user_id": "usr_98231",
|
|
134
|
+
"total_cents": 12500,
|
|
135
|
+
"status": "CREATED"
|
|
136
|
+
},
|
|
137
|
+
"source": {
|
|
138
|
+
"version": "2.5.0.Final",
|
|
139
|
+
"connector": "postgresql",
|
|
140
|
+
"name": "prod_cdc",
|
|
141
|
+
"ts_ms": 1718000000000,
|
|
142
|
+
"snapshot": "false",
|
|
143
|
+
"db": "production_app",
|
|
144
|
+
"schema": "public",
|
|
145
|
+
"table": "orders",
|
|
146
|
+
"txId": 984120,
|
|
147
|
+
"lsn": 104857600
|
|
148
|
+
},
|
|
149
|
+
"op": "c",
|
|
150
|
+
"ts_ms": 1718000000100
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
* `op`: `"c"` (create), `"u"` (update), `"d"` (delete), `"r"` (snapshot read).
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 🛡️ Production Failure Modes & Operational Checklist
|
|
159
|
+
|
|
160
|
+
1. **Replication Slot Disk Exhaustion**:
|
|
161
|
+
- *Risk*: If Kafka Connect crashes, Postgres retains WAL logs indefinitely, filling disk.
|
|
162
|
+
- *Mitigation*: Set `max_slot_wal_keep_size = 50GB` in `postgresql.conf` to protect database uptime.
|
|
163
|
+
2. **Heartbeat Tuning**:
|
|
164
|
+
- Always configure `heartbeat.interval.ms` (e.g. 5000ms) to ensure LSN progression even during low-traffic periods.
|
|
165
|
+
3. **Schema Evolution Handling**:
|
|
166
|
+
- Use Schema Registry (Avro or Protobuf) with `BACKWARD` or `FULL` compatibility to avoid downstream deserialization failures.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: duckdb-local-olap
|
|
3
|
+
description: >-
|
|
4
|
+
Architects, queries, and optimizes embedded in-process DuckDB analytical workflows, direct Parquet/S3 querying, zero-copy Apache Arrow dataframes, and MotherDuck hybrid cloud execution.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# DuckDB Local OLAP & Serverless Analytics
|
|
8
|
+
|
|
9
|
+
This skill guides building high-speed analytical engines using DuckDB—the "SQLite for analytics"—enabling columnar vectorized execution, direct querying of compressed Parquet files on cloud storage, and zero-copy transfers with Apache Arrow.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚡ Core Patterns
|
|
14
|
+
|
|
15
|
+
### 1. Direct Parquet Querying Over S3 Without Ingestion
|
|
16
|
+
|
|
17
|
+
Query gigabytes of remote compressed files with projection and predicate pushdowns (only requested byte ranges are transferred over the network):
|
|
18
|
+
|
|
19
|
+
```sql
|
|
20
|
+
-- 1. Install and load HTTP and S3 extensions
|
|
21
|
+
INSTALL httpfs;
|
|
22
|
+
LOAD httpfs;
|
|
23
|
+
|
|
24
|
+
-- 2. Configure S3 authentication
|
|
25
|
+
SET s3_region = 'us-east-1';
|
|
26
|
+
SET s3_access_key_id = 'YOUR_ACCESS_KEY';
|
|
27
|
+
SET s3_secret_access_key = 'YOUR_SECRET_KEY';
|
|
28
|
+
|
|
29
|
+
-- 3. Query remote Parquet directory with globs
|
|
30
|
+
SELECT
|
|
31
|
+
country,
|
|
32
|
+
count(*) AS total_transactions,
|
|
33
|
+
round(avg(amount_usd), 2) AS avg_amount,
|
|
34
|
+
quantile_cont(amount_usd, 0.95) AS p95_amount
|
|
35
|
+
FROM read_parquet('s3://my-data-lake/transactions/year=2026/month=*/*.parquet')
|
|
36
|
+
WHERE status = 'settled'
|
|
37
|
+
GROUP BY country
|
|
38
|
+
ORDER BY total_transactions DESC
|
|
39
|
+
LIMIT 20;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### 2. Zero-Copy Python & Polars / Arrow Integration
|
|
45
|
+
|
|
46
|
+
Pass memory buffers directly between DuckDB's vectorized engine and Polars or PyArrow without JSON or IPC serialization:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import duckdb
|
|
50
|
+
import polars as pl
|
|
51
|
+
|
|
52
|
+
# Connect to in-memory instance
|
|
53
|
+
con = duckdb.connect()
|
|
54
|
+
|
|
55
|
+
# Set aggressive memory limits and worker threads
|
|
56
|
+
con.execute("SET memory_limit = '8GB';")
|
|
57
|
+
con.execute("SET threads = 8;")
|
|
58
|
+
|
|
59
|
+
# Create a sample Polars DataFrame
|
|
60
|
+
df = pl.DataFrame({
|
|
61
|
+
"user_id": [101, 102, 103],
|
|
62
|
+
"scores": [98.5, 76.2, 89.0]
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
# Query Polars DataFrame directly as a virtual table (zero-copy)
|
|
66
|
+
arrow_table = con.execute("""
|
|
67
|
+
SELECT
|
|
68
|
+
user_id,
|
|
69
|
+
scores,
|
|
70
|
+
CASE WHEN scores >= 90 THEN 'A' ELSE 'B' END AS grade
|
|
71
|
+
FROM df
|
|
72
|
+
WHERE scores > 80
|
|
73
|
+
""").arrow()
|
|
74
|
+
|
|
75
|
+
# Convert back to Polars instantaneously
|
|
76
|
+
result_df = pl.from_arrow(arrow_table)
|
|
77
|
+
print(result_df)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### 3. Node.js Embedded Analytics Engine
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { Database } from 'duckdb-async';
|
|
86
|
+
|
|
87
|
+
export async function aggregateLocalParquet(parquetPath: string) {
|
|
88
|
+
const db = await Database.create(':memory:');
|
|
89
|
+
|
|
90
|
+
const rows = await db.all(`
|
|
91
|
+
SELECT
|
|
92
|
+
category,
|
|
93
|
+
count(*) AS item_count,
|
|
94
|
+
sum(price) AS gross_revenue
|
|
95
|
+
FROM read_parquet(?)
|
|
96
|
+
GROUP BY category
|
|
97
|
+
ORDER BY gross_revenue DESC
|
|
98
|
+
`, [parquetPath]);
|
|
99
|
+
|
|
100
|
+
await db.close();
|
|
101
|
+
return rows;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### 4. MotherDuck Cloud Hybrid Execution
|
|
108
|
+
|
|
109
|
+
Scale seamlessly from a single laptop to collaborative cloud storage without modifying SQL queries:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
import duckdb
|
|
113
|
+
|
|
114
|
+
# Connect to MotherDuck (cloud database)
|
|
115
|
+
con = duckdb.connect("md:production_analytics")
|
|
116
|
+
|
|
117
|
+
# Join local disk Parquet files directly with MotherDuck cloud tables
|
|
118
|
+
con.execute("""
|
|
119
|
+
SELECT
|
|
120
|
+
cloud_users.organization_id,
|
|
121
|
+
count(local_events.event_id) AS event_volume
|
|
122
|
+
FROM read_parquet('./local_cache/*.parquet') AS local_events
|
|
123
|
+
JOIN cloud_users ON local_events.user_id = cloud_users.id
|
|
124
|
+
GROUP BY cloud_users.organization_id
|
|
125
|
+
""")
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 🛠️ Performance Checklist
|
|
131
|
+
|
|
132
|
+
- **Use Parquet Over CSV**: Parquet is 10x-50x faster due to columnar compression, statistics dictionaries, and column skipping.
|
|
133
|
+
- **Configure Memory Limit**: Always set `SET memory_limit = 'XGB';` to ensure DuckDB uses external sorting/joining when data exceeds RAM instead of crashing the process.
|
|
134
|
+
- **Avoid Row-by-Row Inserts**: Use `Appender` or `COPY ... FROM ...` in bulk batches of 50,000+ rows.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fastapi-production
|
|
3
|
+
description: >-
|
|
4
|
+
Architects, builds, and reviews production-grade async FastAPI backends with Pydantic v2, lifespan context management, JWT auth, dependency injection, and health probes.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# FastAPI Production Architect
|
|
8
|
+
|
|
9
|
+
This skill guides building high-performance, asynchronous REST APIs with FastAPI, adhering to production standards, strict type safety with Pydantic v2, clean dependency injection, and cloud-native observability.
|
|
10
|
+
|
|
11
|
+
## 🏗️ Production Directory Layout
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
app/
|
|
15
|
+
├── api/
|
|
16
|
+
│ ├── deps.py # Shared dependencies (DB sessions, current user, rate limiters)
|
|
17
|
+
│ └── v1/
|
|
18
|
+
│ ├── router.py # Root v1 router aggregating feature endpoints
|
|
19
|
+
│ └── endpoints/
|
|
20
|
+
│ ├── auth.py # Authentication & token renewal
|
|
21
|
+
│ └── users.py # User management endpoints
|
|
22
|
+
├── core/
|
|
23
|
+
│ ├── config.py # Pydantic BaseSettings environment validation
|
|
24
|
+
│ ├── database.py # Async SQLAlchemy engine & session factory
|
|
25
|
+
│ └── security.py # JWT encoding/decoding & Argon2/bcrypt hashing
|
|
26
|
+
├── models/ # SQLAlchemy ORM database models
|
|
27
|
+
├── schemas/ # Pydantic v2 request/response schemas
|
|
28
|
+
├── services/ # Pure domain business logic
|
|
29
|
+
└── main.py # FastAPI application initialization & lifespan
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## ⚡ Core Patterns
|
|
35
|
+
|
|
36
|
+
### 1. Lifespan State Management
|
|
37
|
+
|
|
38
|
+
Avoid deprecated `@app.on_event("startup")` and `@app.on_event("shutdown")`. Use modern async context lifespans:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from contextlib import asynccontextmanager
|
|
42
|
+
from fastapi import FastAPI
|
|
43
|
+
from app.core.database import engine
|
|
44
|
+
from app.core.redis import init_redis_pool, close_redis_pool
|
|
45
|
+
|
|
46
|
+
@asynccontextmanager
|
|
47
|
+
async def lifespan(app: FastAPI):
|
|
48
|
+
# Startup: Initialize connection pools, caches, and telemetry
|
|
49
|
+
app.state.redis = await init_redis_pool()
|
|
50
|
+
try:
|
|
51
|
+
yield
|
|
52
|
+
finally:
|
|
53
|
+
# Shutdown: Gracefully drain connections
|
|
54
|
+
await close_redis_pool(app.state.redis)
|
|
55
|
+
await engine.dispose()
|
|
56
|
+
|
|
57
|
+
app = FastAPI(title="Production Service", lifespan=lifespan)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Pydantic v2 Request & Response Schemas
|
|
61
|
+
|
|
62
|
+
Enforce strict validation, immutable attributes where appropriate, and forbid undeclared payloads:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from pydantic import BaseModel, ConfigDict, EmailStr, Field
|
|
66
|
+
|
|
67
|
+
class UserBase(BaseModel):
|
|
68
|
+
model_config = ConfigDict(
|
|
69
|
+
from_attributes=True,
|
|
70
|
+
extra="forbid",
|
|
71
|
+
str_strip_whitespace=True,
|
|
72
|
+
)
|
|
73
|
+
email: EmailStr
|
|
74
|
+
is_active: bool = True
|
|
75
|
+
|
|
76
|
+
class UserCreate(UserBase):
|
|
77
|
+
password: str = Field(min_length=8, max_length=128)
|
|
78
|
+
|
|
79
|
+
class UserResponse(UserBase):
|
|
80
|
+
id: int
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 3. Dependency Injection & Database Sessions
|
|
84
|
+
|
|
85
|
+
Inject asynchronous SQLAlchemy sessions using an `async_sessionmaker` generator yielding into FastAPI's `Depends`:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from collections.abc import AsyncGenerator
|
|
89
|
+
from fastapi import Depends
|
|
90
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
91
|
+
from app.core.database import async_session_factory
|
|
92
|
+
|
|
93
|
+
async def get_db_session() -> AsyncGenerator[AsyncSession, None]:
|
|
94
|
+
async with async_session_factory() as session:
|
|
95
|
+
try:
|
|
96
|
+
yield session
|
|
97
|
+
await session.commit()
|
|
98
|
+
except Exception:
|
|
99
|
+
await session.rollback()
|
|
100
|
+
raise
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 4. JWT Authentication & Permission Guards
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from typing import Annotated
|
|
107
|
+
from fastapi import Depends, HTTPException, status
|
|
108
|
+
from fastapi.security import OAuth2PasswordBearer
|
|
109
|
+
from app.schemas.user import UserResponse
|
|
110
|
+
from app.services.auth import decode_jwt_token
|
|
111
|
+
|
|
112
|
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
|
|
113
|
+
|
|
114
|
+
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]) -> UserResponse:
|
|
115
|
+
user = await decode_jwt_token(token)
|
|
116
|
+
if not user or not user.is_active:
|
|
117
|
+
raise HTTPException(
|
|
118
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
119
|
+
detail="Invalid authentication credentials",
|
|
120
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
121
|
+
)
|
|
122
|
+
return user
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 5. Standardized Problem Details Error Envelope (RFC 7807)
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from fastapi import Request
|
|
129
|
+
from fastapi.responses import JSONResponse
|
|
130
|
+
|
|
131
|
+
async def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
|
132
|
+
return JSONResponse(
|
|
133
|
+
status_code=500,
|
|
134
|
+
content={
|
|
135
|
+
"type": "https://errors.example.com/internal-server-error",
|
|
136
|
+
"title": "Internal Server Error",
|
|
137
|
+
"status": 500,
|
|
138
|
+
"detail": "An unexpected error occurred. Please contact engineering support.",
|
|
139
|
+
"instance": str(request.url.path),
|
|
140
|
+
},
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 6. Kubernetes Liveness & Readiness Probes
|
|
145
|
+
|
|
146
|
+
Expose separate endpoints for orchestrator checks:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
@app.get("/healthz/liveness", tags=["Health"])
|
|
150
|
+
async def liveness_check():
|
|
151
|
+
return {"status": "ok"}
|
|
152
|
+
|
|
153
|
+
@app.get("/healthz/readiness", tags=["Health"])
|
|
154
|
+
async def readiness_check(db: AsyncSession = Depends(get_db_session)):
|
|
155
|
+
await db.execute(text("SELECT 1"))
|
|
156
|
+
return {"status": "ready"}
|
|
157
|
+
```
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grpc-connect-rpc
|
|
3
|
+
description: >-
|
|
4
|
+
Architects and implements high-performance, browser-compatible gRPC and Protocol Buffer services using Connect-RPC (Connect-ES & Connect-Go), HTTP/2 & HTTP/3 streaming, and type-safe schema generation.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Connect-RPC & Modern Protocol Buffers
|
|
8
|
+
|
|
9
|
+
This skill guides building fast, ergonomic, and 100% browser-compatible RPC services using Connect-RPC (by Buf). Connect implements the gRPC, gRPC-Web, and Connect protocols natively over HTTP/1.1, HTTP/2, and HTTP/3 without requiring Envoy proxy sidecars.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚡ Core Patterns
|
|
14
|
+
|
|
15
|
+
### 1. Protobuf Service Definition (`buf.build` Standard)
|
|
16
|
+
|
|
17
|
+
Define service contracts and strongly-typed data structures:
|
|
18
|
+
|
|
19
|
+
```protobuf
|
|
20
|
+
// proto/commerce/v1/order.proto
|
|
21
|
+
syntax = "proto3";
|
|
22
|
+
|
|
23
|
+
package commerce.v1;
|
|
24
|
+
|
|
25
|
+
option go_package = "github.com/company/commerce/gen/commerce/v1;commercev1";
|
|
26
|
+
|
|
27
|
+
service OrderService {
|
|
28
|
+
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
|
|
29
|
+
rpc StreamOrderUpdates(StreamOrderUpdatesRequest) returns (stream StreamOrderUpdatesResponse);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
message CreateOrderRequest {
|
|
33
|
+
string customer_id = 1;
|
|
34
|
+
repeated OrderItem items = 2;
|
|
35
|
+
double total_usd = 3;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
message OrderItem {
|
|
39
|
+
string sku = 1;
|
|
40
|
+
int32 quantity = 2;
|
|
41
|
+
double price_usd = 3;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
message CreateOrderResponse {
|
|
45
|
+
string order_id = 1;
|
|
46
|
+
string status = 2;
|
|
47
|
+
int64 created_at_unix = 3;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
message StreamOrderUpdatesRequest {
|
|
51
|
+
string order_id = 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
message StreamOrderUpdatesResponse {
|
|
55
|
+
string order_id = 1;
|
|
56
|
+
string current_status = 2;
|
|
57
|
+
string message = 3;
|
|
58
|
+
int64 timestamp = 4;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Compile with `buf generate`:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# buf.gen.yaml
|
|
66
|
+
version: v2
|
|
67
|
+
plugins:
|
|
68
|
+
- local: protoc-gen-es
|
|
69
|
+
out: gen/ts
|
|
70
|
+
opt: target=ts
|
|
71
|
+
- local: protoc-gen-connect-es
|
|
72
|
+
out: gen/ts
|
|
73
|
+
opt: target=ts
|
|
74
|
+
- local: protoc-gen-go
|
|
75
|
+
out: gen/go
|
|
76
|
+
opt: paths=source_relative
|
|
77
|
+
- local: protoc-gen-connect-go
|
|
78
|
+
out: gen/go
|
|
79
|
+
opt: paths=source_relative
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### 2. Node.js / TypeScript Server Implementation (Connect-ES)
|
|
85
|
+
|
|
86
|
+
Implement the typed service handler with zero boilerplate:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { ConnectRouter } from '@connectrpc/connect';
|
|
90
|
+
import { OrderService } from './gen/ts/commerce/v1/order_connect';
|
|
91
|
+
import { fastify } from 'fastify';
|
|
92
|
+
import { fastifyConnectPlugin } from '@connectrpc/connect-fastify';
|
|
93
|
+
|
|
94
|
+
function routes(router: ConnectRouter) {
|
|
95
|
+
router.service(OrderService, {
|
|
96
|
+
async createOrder(req) {
|
|
97
|
+
if (!req.customerId || req.items.length === 0) {
|
|
98
|
+
throw new ConnectError('Order must contain a customerId and items', Code.InvalidArgument);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const orderId = `ord_${crypto.randomUUID().slice(0, 8)}`;
|
|
102
|
+
return {
|
|
103
|
+
orderId,
|
|
104
|
+
status: 'PENDING_PAYMENT',
|
|
105
|
+
createdAtUnix: BigInt(Date.now()),
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
async *streamOrderUpdates(req) {
|
|
110
|
+
const statuses = ['PAYMENT_CONFIRMED', 'WAREHOUSE_PICKED', 'IN_TRANSIT', 'DELIVERED'];
|
|
111
|
+
for (const status of statuses) {
|
|
112
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
113
|
+
yield {
|
|
114
|
+
orderId: req.orderId,
|
|
115
|
+
currentStatus: status,
|
|
116
|
+
message: `Package status updated to ${status}`,
|
|
117
|
+
timestamp: BigInt(Date.now()),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const server = fastify({ http2: true });
|
|
125
|
+
await server.register(fastifyConnectPlugin, { routes });
|
|
126
|
+
await server.listen({ host: '0.0.0.0', port: 8080 });
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### 3. Native Browser Client (No Envoy Proxy Needed)
|
|
132
|
+
|
|
133
|
+
Invoke typed RPCs directly from modern browsers or Next.js applications:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { createClient } from '@connectrpc/connect';
|
|
137
|
+
import { createConnectTransport } from '@connectrpc/connect-web';
|
|
138
|
+
import { OrderService } from './gen/ts/commerce/v1/order_connect';
|
|
139
|
+
|
|
140
|
+
// Transport supports pure HTTP POST requests with JSON or binary Protobuf envelopes
|
|
141
|
+
const transport = createConnectTransport({
|
|
142
|
+
baseUrl: 'https://api.example.com',
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const client = createClient(OrderService, transport);
|
|
146
|
+
|
|
147
|
+
// 1. Unary RPC Call
|
|
148
|
+
const response = await client.createOrder({
|
|
149
|
+
customerId: 'cust_98234',
|
|
150
|
+
items: [{ sku: 'CLOUD-GPU-A100', quantity: 2, priceUsd: 1450.0 }],
|
|
151
|
+
totalUsd: 2900.0,
|
|
152
|
+
});
|
|
153
|
+
console.log('Created order:', response.orderId);
|
|
154
|
+
|
|
155
|
+
// 2. Server Streaming RPC Call
|
|
156
|
+
for await (const update of client.streamOrderUpdates({ orderId: response.orderId })) {
|
|
157
|
+
console.log(`Live Status [${update.currentStatus}]: ${update.message}`);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 🎯 Verification & Diagnostics
|
|
164
|
+
|
|
165
|
+
1. **Test Service with cURL (Standard HTTP POST)**:
|
|
166
|
+
```bash
|
|
167
|
+
curl \
|
|
168
|
+
--header "Content-Type: application/json" \
|
|
169
|
+
--data '{"customerId": "cust_123", "items": [{"sku": "PROD-1", "quantity": 1, "priceUsd": 99.0}], "totalUsd": 99.0}' \
|
|
170
|
+
https://api.example.com/commerce.v1.OrderService/CreateOrder
|
|
171
|
+
```
|
|
172
|
+
2. **Inspect Buf Lint & Breaking Change Rules**:
|
|
173
|
+
```bash
|
|
174
|
+
buf lint
|
|
175
|
+
buf breaking --against ".git#branch=main"
|
|
176
|
+
```
|