@knowledgine/cli 0.1.0 → 0.2.1
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/dist/commands/capture.d.ts +23 -0
- package/dist/commands/capture.d.ts.map +1 -0
- package/dist/commands/capture.js +237 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/demo.d.ts +6 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +48 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/feedback.d.ts +27 -0
- package/dist/commands/feedback.d.ts.map +1 -0
- package/dist/commands/feedback.js +120 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/ingest.d.ts +9 -0
- package/dist/commands/ingest.d.ts.map +1 -0
- package/dist/commands/ingest.js +162 -0
- package/dist/commands/ingest.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +327 -42
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/plugins.d.ts +6 -0
- package/dist/commands/plugins.d.ts.map +1 -0
- package/dist/commands/plugins.js +41 -0
- package/dist/commands/plugins.js.map +1 -0
- package/dist/commands/search.d.ts +16 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +140 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/setup.d.ts +57 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +331 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +1 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +98 -24
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +149 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/tool.d.ts +29 -0
- package/dist/commands/tool.d.ts.map +1 -0
- package/dist/commands/tool.js +247 -0
- package/dist/commands/tool.js.map +1 -0
- package/dist/commands/upgrade.d.ts +6 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +137 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/index.js +178 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/demo-manager.d.ts +16 -0
- package/dist/lib/demo-manager.d.ts.map +1 -0
- package/dist/lib/demo-manager.js +37 -0
- package/dist/lib/demo-manager.js.map +1 -0
- package/dist/lib/entity-extractor.d.ts +15 -0
- package/dist/lib/entity-extractor.d.ts.map +1 -0
- package/dist/lib/entity-extractor.js +86 -0
- package/dist/lib/entity-extractor.js.map +1 -0
- package/dist/lib/formatter.d.ts +7 -0
- package/dist/lib/formatter.d.ts.map +1 -0
- package/dist/lib/formatter.js +94 -0
- package/dist/lib/formatter.js.map +1 -0
- package/dist/lib/indexer.d.ts +6 -1
- package/dist/lib/indexer.d.ts.map +1 -1
- package/dist/lib/indexer.js +4 -1
- package/dist/lib/indexer.js.map +1 -1
- package/dist/lib/ingest-watcher.d.ts +20 -0
- package/dist/lib/ingest-watcher.d.ts.map +1 -0
- package/dist/lib/ingest-watcher.js +45 -0
- package/dist/lib/ingest-watcher.js.map +1 -0
- package/dist/lib/plugin-loader.d.ts +5 -0
- package/dist/lib/plugin-loader.d.ts.map +1 -0
- package/dist/lib/plugin-loader.js +27 -0
- package/dist/lib/plugin-loader.js.map +1 -0
- package/dist/lib/progress.d.ts +63 -0
- package/dist/lib/progress.d.ts.map +1 -0
- package/dist/lib/progress.js +228 -0
- package/dist/lib/progress.js.map +1 -0
- package/dist/lib/ui/box.d.ts +7 -0
- package/dist/lib/ui/box.d.ts.map +1 -0
- package/dist/lib/ui/box.js +19 -0
- package/dist/lib/ui/box.js.map +1 -0
- package/dist/lib/ui/error-formatter.d.ts +8 -0
- package/dist/lib/ui/error-formatter.d.ts.map +1 -0
- package/dist/lib/ui/error-formatter.js +21 -0
- package/dist/lib/ui/error-formatter.js.map +1 -0
- package/dist/lib/ui/index.d.ts +7 -0
- package/dist/lib/ui/index.d.ts.map +1 -0
- package/dist/lib/ui/index.js +7 -0
- package/dist/lib/ui/index.js.map +1 -0
- package/dist/lib/ui/output.d.ts +2 -0
- package/dist/lib/ui/output.d.ts.map +1 -0
- package/dist/lib/ui/output.js +4 -0
- package/dist/lib/ui/output.js.map +1 -0
- package/dist/lib/ui/spinner.d.ts +4 -0
- package/dist/lib/ui/spinner.d.ts.map +1 -0
- package/dist/lib/ui/spinner.js +5 -0
- package/dist/lib/ui/spinner.js.map +1 -0
- package/dist/lib/ui/table.d.ts +9 -0
- package/dist/lib/ui/table.d.ts.map +1 -0
- package/dist/lib/ui/table.js +28 -0
- package/dist/lib/ui/table.js.map +1 -0
- package/dist/lib/ui/theme.d.ts +21 -0
- package/dist/lib/ui/theme.d.ts.map +1 -0
- package/dist/lib/ui/theme.js +29 -0
- package/dist/lib/ui/theme.js.map +1 -0
- package/dist/lib/unknown-command-handler.d.ts +14 -0
- package/dist/lib/unknown-command-handler.d.ts.map +1 -0
- package/dist/lib/unknown-command-handler.js +25 -0
- package/dist/lib/unknown-command-handler.js.map +1 -0
- package/dist/lib/url-validator.d.ts +2 -0
- package/dist/lib/url-validator.d.ts.map +1 -0
- package/dist/lib/url-validator.js +21 -0
- package/dist/lib/url-validator.js.map +1 -0
- package/fixtures/demo/notes/api-design-decisions.md +84 -0
- package/fixtures/demo/notes/auth-debugging.md +60 -0
- package/fixtures/demo/notes/ci-cd-pipeline.md +97 -0
- package/fixtures/demo/notes/code-review-notes.md +78 -0
- package/fixtures/demo/notes/database-optimization.md +81 -0
- package/fixtures/demo/notes/docker-troubleshooting.md +80 -0
- package/fixtures/demo/notes/react-performance.md +67 -0
- package/fixtures/demo/notes/typescript-migration.md +89 -0
- package/package.json +13 -4
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- api
|
|
4
|
+
- rest
|
|
5
|
+
- design
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: backend-api
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# REST API Design Decisions
|
|
11
|
+
|
|
12
|
+
## Issue: Pagination Strategy
|
|
13
|
+
|
|
14
|
+
Needed to decide between offset-based and cursor-based pagination
|
|
15
|
+
for the search results endpoint.
|
|
16
|
+
|
|
17
|
+
### Decision: Cursor-based pagination
|
|
18
|
+
|
|
19
|
+
Offset pagination breaks when items are inserted/deleted during browsing.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// Cursor-based pagination
|
|
23
|
+
interface PaginatedResponse<T> {
|
|
24
|
+
data: T[];
|
|
25
|
+
cursor: string | null; // null means no more pages
|
|
26
|
+
hasMore: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
app.get("/api/notes", (req, res) => {
|
|
30
|
+
const { cursor, limit = 20 } = req.query;
|
|
31
|
+
const decoded = cursor ? decodeCursor(cursor) : null;
|
|
32
|
+
|
|
33
|
+
const notes = db.query(
|
|
34
|
+
`SELECT * FROM notes
|
|
35
|
+
WHERE ($1::text IS NULL OR id < $1)
|
|
36
|
+
ORDER BY id DESC LIMIT $2`,
|
|
37
|
+
[decoded?.id, limit + 1],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const hasMore = notes.length > limit;
|
|
41
|
+
const data = notes.slice(0, limit);
|
|
42
|
+
|
|
43
|
+
res.json({
|
|
44
|
+
data,
|
|
45
|
+
cursor: hasMore ? encodeCursor(data.at(-1)) : null,
|
|
46
|
+
hasMore,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Issue: Error Response Format
|
|
52
|
+
|
|
53
|
+
Standardized error responses across all endpoints.
|
|
54
|
+
|
|
55
|
+
### Solution: RFC 7807 Problem Details
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface ProblemDetail {
|
|
59
|
+
type: string;
|
|
60
|
+
title: string;
|
|
61
|
+
status: number;
|
|
62
|
+
detail: string;
|
|
63
|
+
instance?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Error handler middleware
|
|
67
|
+
app.use((err, req, res, _next) => {
|
|
68
|
+
const problem: ProblemDetail = {
|
|
69
|
+
type: `https://api.example.com/errors/${err.code}`,
|
|
70
|
+
title: err.title || "Internal Server Error",
|
|
71
|
+
status: err.status || 500,
|
|
72
|
+
detail: err.message,
|
|
73
|
+
instance: req.originalUrl,
|
|
74
|
+
};
|
|
75
|
+
res.status(problem.status).json(problem);
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Learnings
|
|
80
|
+
|
|
81
|
+
- Cursor-based pagination is more reliable for real-time data
|
|
82
|
+
- Consistent error formats reduce client-side error handling complexity
|
|
83
|
+
- Always version your API from the start (`/v1/`)
|
|
84
|
+
- Document decisions in ADRs for future team members
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- authentication
|
|
4
|
+
- jwt
|
|
5
|
+
- debugging
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: backend-api
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Authentication Debugging Session
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
JWT token validation was failing intermittently in production.
|
|
15
|
+
Users reported being logged out randomly after 10-15 minutes,
|
|
16
|
+
even though the token expiry was set to 1 hour.
|
|
17
|
+
|
|
18
|
+
### Error Log
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
Error: TokenExpiredError: jwt expired
|
|
22
|
+
at /app/middleware/auth.ts:42:11
|
|
23
|
+
at processTicksAndRejections (node:internal/process/task_queues:95:5)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Investigation
|
|
27
|
+
|
|
28
|
+
- Checked server clock sync — NTP was configured correctly
|
|
29
|
+
- Compared token `iat` (issued at) timestamps with server time
|
|
30
|
+
- Found a 45-minute clock skew between API server and auth service
|
|
31
|
+
|
|
32
|
+
## Solution
|
|
33
|
+
|
|
34
|
+
The auth service was running in a container with a drifted system clock.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// Added clock tolerance to JWT verification
|
|
38
|
+
const decoded = jwt.verify(token, SECRET, {
|
|
39
|
+
clockTolerance: 60, // allow 60 seconds of clock skew
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Also fixed the root cause by enabling NTP sync in the Docker container:
|
|
44
|
+
|
|
45
|
+
```dockerfile
|
|
46
|
+
RUN apt-get update && apt-get install -y ntpdate
|
|
47
|
+
CMD ntpdate -s pool.ntp.org && node server.js
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Learnings
|
|
51
|
+
|
|
52
|
+
- Always configure clock tolerance for distributed JWT validation
|
|
53
|
+
- Container clocks can drift if the host NTP is not propagated
|
|
54
|
+
- Add monitoring for clock skew between services
|
|
55
|
+
- The `clockTolerance` option is safer than extending token expiry
|
|
56
|
+
|
|
57
|
+
## Time Spent
|
|
58
|
+
|
|
59
|
+
Investigation: 2 hours
|
|
60
|
+
Fix + deployment: 30 minutes
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- ci-cd
|
|
4
|
+
- github-actions
|
|
5
|
+
- testing
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: infrastructure
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# CI/CD Pipeline Setup and Debugging
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
The CI pipeline was taking 25 minutes per push, blocking the
|
|
15
|
+
development workflow. Flaky tests caused unnecessary re-runs.
|
|
16
|
+
|
|
17
|
+
## Investigation
|
|
18
|
+
|
|
19
|
+
Analyzed GitHub Actions run logs:
|
|
20
|
+
|
|
21
|
+
- Dependency install: 4 minutes (no caching)
|
|
22
|
+
- Build: 3 minutes
|
|
23
|
+
- Tests: 15 minutes (sequential, with 3 flaky tests)
|
|
24
|
+
- Deploy: 3 minutes
|
|
25
|
+
|
|
26
|
+
## Solution: Optimized Pipeline
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
# .github/workflows/ci.yml
|
|
30
|
+
name: CI
|
|
31
|
+
on: [push, pull_request]
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
build-and-test:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
|
|
39
|
+
- uses: pnpm/action-setup@v4
|
|
40
|
+
with:
|
|
41
|
+
version: 9
|
|
42
|
+
|
|
43
|
+
- uses: actions/setup-node@v4
|
|
44
|
+
with:
|
|
45
|
+
node-version: 20
|
|
46
|
+
cache: "pnpm"
|
|
47
|
+
|
|
48
|
+
- run: pnpm install --frozen-lockfile
|
|
49
|
+
|
|
50
|
+
- run: pnpm build
|
|
51
|
+
|
|
52
|
+
- run: pnpm test:run --reporter=verbose
|
|
53
|
+
env:
|
|
54
|
+
CI: true
|
|
55
|
+
|
|
56
|
+
lint:
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
- uses: pnpm/action-setup@v4
|
|
61
|
+
- run: pnpm install --frozen-lockfile
|
|
62
|
+
- run: pnpm lint
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Flaky Test Fix
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Before: timing-dependent test
|
|
69
|
+
it("should debounce input", async () => {
|
|
70
|
+
fireEvent.change(input, { target: { value: "test" } });
|
|
71
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
72
|
+
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// After: deterministic with fake timers
|
|
76
|
+
it("should debounce input", () => {
|
|
77
|
+
vi.useFakeTimers();
|
|
78
|
+
fireEvent.change(input, { target: { value: "test" } });
|
|
79
|
+
vi.advanceTimersByTime(300);
|
|
80
|
+
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
81
|
+
vi.useRealTimers();
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Results
|
|
86
|
+
|
|
87
|
+
- Pipeline time: 25 min → 8 min (68% reduction)
|
|
88
|
+
- Flaky test rate: 15% → 0%
|
|
89
|
+
- Developer satisfaction significantly improved
|
|
90
|
+
|
|
91
|
+
## Learnings
|
|
92
|
+
|
|
93
|
+
- Cache dependencies aggressively in CI
|
|
94
|
+
- Run lint and tests in parallel jobs
|
|
95
|
+
- Flaky tests erode trust — fix them immediately
|
|
96
|
+
- Use `--frozen-lockfile` to catch dependency drift
|
|
97
|
+
- Fake timers eliminate timing-based flakiness
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- code-review
|
|
4
|
+
- best-practices
|
|
5
|
+
- team
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: team-process
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Code Review Guidelines and Common Issues
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
Code reviews were inconsistent. Some PRs got rubber-stamped while
|
|
15
|
+
others received 50+ nitpick comments. Reviews took 2-3 days on average.
|
|
16
|
+
|
|
17
|
+
## Solution: Review Checklist
|
|
18
|
+
|
|
19
|
+
### What to Check
|
|
20
|
+
|
|
21
|
+
1. **Correctness**: Does the code do what the PR description says?
|
|
22
|
+
2. **Edge cases**: Null handling, empty arrays, boundary conditions
|
|
23
|
+
3. **Security**: Input validation, SQL injection, XSS
|
|
24
|
+
4. **Tests**: Are new behaviors covered? Are edge cases tested?
|
|
25
|
+
5. **Naming**: Do variable/function names convey intent?
|
|
26
|
+
|
|
27
|
+
### Common Issues Found in Reviews
|
|
28
|
+
|
|
29
|
+
#### Error handling gaps
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Bad: swallows errors silently
|
|
33
|
+
try {
|
|
34
|
+
await saveUser(data);
|
|
35
|
+
} catch {
|
|
36
|
+
// ignore
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Good: handle or propagate with context
|
|
40
|
+
try {
|
|
41
|
+
await saveUser(data);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
logger.error("Failed to save user", { userId: data.id, error });
|
|
44
|
+
throw new ServiceError("User save failed", { cause: error });
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### Missing input validation
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Bad: trusts external input
|
|
52
|
+
app.post("/api/users", (req, res) => {
|
|
53
|
+
db.query("INSERT INTO users (name) VALUES ($1)", [req.body.name]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Good: validate before processing
|
|
57
|
+
app.post("/api/users", (req, res) => {
|
|
58
|
+
const { name } = req.body;
|
|
59
|
+
if (!name || typeof name !== "string" || name.length > 255) {
|
|
60
|
+
return res.status(400).json({ error: "Invalid name" });
|
|
61
|
+
}
|
|
62
|
+
db.query("INSERT INTO users (name) VALUES ($1)", [name]);
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Process Improvements
|
|
67
|
+
|
|
68
|
+
- Max review turnaround: 4 hours for small PRs, 1 day for large
|
|
69
|
+
- Use "Request changes" only for blocking issues
|
|
70
|
+
- Prefix comments: `nit:`, `question:`, `suggestion:`, `blocking:`
|
|
71
|
+
- Author should self-review before requesting review
|
|
72
|
+
|
|
73
|
+
## Learnings
|
|
74
|
+
|
|
75
|
+
- Checklists reduce review inconsistency
|
|
76
|
+
- Small PRs (< 300 lines) get better reviews and faster merges
|
|
77
|
+
- Automate what you can (linting, formatting, type checking)
|
|
78
|
+
- Focus reviews on logic and design, not style
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- database
|
|
4
|
+
- sql
|
|
5
|
+
- performance
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: backend-api
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# SQL Query Optimization and Indexing
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
The notes search endpoint was timing out with 100k+ rows.
|
|
15
|
+
Average query time was 4.2 seconds, causing user-visible latency.
|
|
16
|
+
|
|
17
|
+
### Slow Query
|
|
18
|
+
|
|
19
|
+
```sql
|
|
20
|
+
SELECT n.*, COUNT(p.id) as pattern_count
|
|
21
|
+
FROM notes n
|
|
22
|
+
LEFT JOIN patterns p ON p.note_id = n.id
|
|
23
|
+
WHERE n.content LIKE '%typescript%'
|
|
24
|
+
AND n.created_at > '2024-01-01'
|
|
25
|
+
GROUP BY n.id
|
|
26
|
+
ORDER BY n.created_at DESC
|
|
27
|
+
LIMIT 20;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Investigation
|
|
31
|
+
|
|
32
|
+
Used `EXPLAIN ANALYZE` to identify bottlenecks:
|
|
33
|
+
|
|
34
|
+
```sql
|
|
35
|
+
EXPLAIN ANALYZE SELECT ...;
|
|
36
|
+
-- Seq Scan on notes (cost=0.00..12847.00 rows=100234 width=412)
|
|
37
|
+
-- Filter: (content ~~ '%typescript%')
|
|
38
|
+
-- Rows Removed by Filter: 95102
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The sequential scan was reading every row.
|
|
42
|
+
|
|
43
|
+
## Solution: Indexing Strategy
|
|
44
|
+
|
|
45
|
+
```sql
|
|
46
|
+
-- 1. B-tree index for date range queries
|
|
47
|
+
CREATE INDEX idx_notes_created_at ON notes (created_at DESC);
|
|
48
|
+
|
|
49
|
+
-- 2. Full-text search index instead of LIKE
|
|
50
|
+
CREATE INDEX idx_notes_content_fts ON notes
|
|
51
|
+
USING GIN (to_tsvector('english', content));
|
|
52
|
+
|
|
53
|
+
-- 3. Covering index for the common query pattern
|
|
54
|
+
CREATE INDEX idx_patterns_note_id ON patterns (note_id);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Rewritten Query
|
|
58
|
+
|
|
59
|
+
```sql
|
|
60
|
+
SELECT n.*, COUNT(p.id) as pattern_count
|
|
61
|
+
FROM notes n
|
|
62
|
+
LEFT JOIN patterns p ON p.note_id = n.id
|
|
63
|
+
WHERE to_tsvector('english', n.content) @@ plainto_tsquery('typescript')
|
|
64
|
+
AND n.created_at > '2024-01-01'
|
|
65
|
+
GROUP BY n.id
|
|
66
|
+
ORDER BY n.created_at DESC
|
|
67
|
+
LIMIT 20;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Results
|
|
71
|
+
|
|
72
|
+
- Query time: 4.2s → 18ms (233x improvement)
|
|
73
|
+
- Index storage overhead: ~45MB (acceptable for 100k rows)
|
|
74
|
+
|
|
75
|
+
## Learnings
|
|
76
|
+
|
|
77
|
+
- `LIKE '%term%'` cannot use indexes — always use full-text search
|
|
78
|
+
- `EXPLAIN ANALYZE` is the first tool to reach for
|
|
79
|
+
- Covering indexes avoid table lookups for frequently joined columns
|
|
80
|
+
- Monitor index bloat in write-heavy tables
|
|
81
|
+
- Partial indexes can save space when queries filter on a condition
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- docker
|
|
4
|
+
- networking
|
|
5
|
+
- devops
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: microservices
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Docker Container Networking Issues
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
Containers in docker-compose could not communicate with each other.
|
|
15
|
+
The API service failed to connect to the database container.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Error: connect ECONNREFUSED 127.0.0.1:5432
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Investigation
|
|
22
|
+
|
|
23
|
+
- Verified both containers were running: `docker ps` showed healthy status
|
|
24
|
+
- Checked network: `docker network ls` showed custom bridge network
|
|
25
|
+
- The API was using `localhost` instead of the service name
|
|
26
|
+
|
|
27
|
+
## Solution
|
|
28
|
+
|
|
29
|
+
Docker containers have their own network namespace. Use the service
|
|
30
|
+
name as the hostname, not `localhost`.
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
# docker-compose.yml
|
|
34
|
+
services:
|
|
35
|
+
api:
|
|
36
|
+
build: ./api
|
|
37
|
+
environment:
|
|
38
|
+
# Wrong: DB_HOST=localhost
|
|
39
|
+
DB_HOST: postgres # Use service name
|
|
40
|
+
DB_PORT: 5432
|
|
41
|
+
depends_on:
|
|
42
|
+
postgres:
|
|
43
|
+
condition: service_healthy
|
|
44
|
+
|
|
45
|
+
postgres:
|
|
46
|
+
image: postgres:16
|
|
47
|
+
healthcheck:
|
|
48
|
+
test: ["CMD-SHELL", "pg_isready -U app"]
|
|
49
|
+
interval: 5s
|
|
50
|
+
timeout: 3s
|
|
51
|
+
retries: 5
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Additional Fix: DNS Resolution Timing
|
|
55
|
+
|
|
56
|
+
Even with correct hostnames, the API started before DNS was ready.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// Added retry logic for database connection
|
|
60
|
+
async function connectWithRetry(maxRetries = 5): Promise<Pool> {
|
|
61
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
62
|
+
try {
|
|
63
|
+
const pool = new Pool({ host: process.env.DB_HOST });
|
|
64
|
+
await pool.query("SELECT 1");
|
|
65
|
+
return pool;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.log(`DB connection attempt ${i + 1} failed, retrying...`);
|
|
68
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
throw new Error("Could not connect to database");
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Learnings
|
|
76
|
+
|
|
77
|
+
- Never use `localhost` for inter-container communication
|
|
78
|
+
- Use `depends_on` with health checks, not just service ordering
|
|
79
|
+
- Add connection retry logic for resilience
|
|
80
|
+
- `docker network inspect` is useful for debugging DNS issues
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- react
|
|
4
|
+
- performance
|
|
5
|
+
- frontend
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: dashboard-app
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# React Performance Optimization
|
|
11
|
+
|
|
12
|
+
## Issue
|
|
13
|
+
|
|
14
|
+
The dashboard page was taking 3+ seconds to render with 500 items.
|
|
15
|
+
React DevTools Profiler showed excessive re-renders on every state change.
|
|
16
|
+
|
|
17
|
+
## Root Cause Analysis
|
|
18
|
+
|
|
19
|
+
1. Parent component state changes triggered full list re-render
|
|
20
|
+
2. Inline arrow functions in JSX created new references each render
|
|
21
|
+
3. Large bundle size from importing entire icon library
|
|
22
|
+
|
|
23
|
+
## Fix: Memoization
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
// Before: re-renders on every parent state change
|
|
27
|
+
const ListItem = ({ item, onClick }) => <div onClick={() => onClick(item.id)}>{item.name}</div>;
|
|
28
|
+
|
|
29
|
+
// After: memoized with stable callback
|
|
30
|
+
const ListItem = React.memo(({ item, onClick }) => <div onClick={onClick}>{item.name}</div>);
|
|
31
|
+
|
|
32
|
+
// Parent: stable callback reference
|
|
33
|
+
const handleClick = useCallback((id: string) => {
|
|
34
|
+
setSelectedId(id);
|
|
35
|
+
}, []);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Fix: Code Splitting
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
// Before: eager import
|
|
42
|
+
import { AnalyticsChart } from "./AnalyticsChart";
|
|
43
|
+
|
|
44
|
+
// After: lazy loaded
|
|
45
|
+
const AnalyticsChart = React.lazy(() => import("./AnalyticsChart"));
|
|
46
|
+
|
|
47
|
+
function Dashboard() {
|
|
48
|
+
return (
|
|
49
|
+
<Suspense fallback={<Skeleton />}>
|
|
50
|
+
<AnalyticsChart data={data} />
|
|
51
|
+
</Suspense>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Results
|
|
57
|
+
|
|
58
|
+
- Initial render: 3.2s → 0.8s (75% improvement)
|
|
59
|
+
- Re-render on selection: 450ms → 12ms
|
|
60
|
+
- Bundle size: 1.2MB → 680KB
|
|
61
|
+
|
|
62
|
+
## Learnings
|
|
63
|
+
|
|
64
|
+
- Profile before optimizing — measure actual bottlenecks
|
|
65
|
+
- React.memo only helps when props are actually stable
|
|
66
|
+
- Lazy loading is most effective for below-the-fold content
|
|
67
|
+
- Tree-shaking icon libraries saves significant bundle size
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- typescript
|
|
4
|
+
- migration
|
|
5
|
+
- refactoring
|
|
6
|
+
author: demo-user
|
|
7
|
+
project: legacy-app
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# JavaScript to TypeScript Migration
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
The legacy Express app (50+ files) had no type safety. Runtime errors
|
|
15
|
+
were discovered only in production, and onboarding new developers
|
|
16
|
+
took weeks due to lack of type documentation.
|
|
17
|
+
|
|
18
|
+
## Migration Strategy
|
|
19
|
+
|
|
20
|
+
Adopted an incremental approach instead of a big-bang rewrite.
|
|
21
|
+
|
|
22
|
+
### Phase 1: Setup (Day 1)
|
|
23
|
+
|
|
24
|
+
```jsonc
|
|
25
|
+
// tsconfig.json - permissive start
|
|
26
|
+
{
|
|
27
|
+
"compilerOptions": {
|
|
28
|
+
"allowJs": true,
|
|
29
|
+
"checkJs": false,
|
|
30
|
+
"strict": false,
|
|
31
|
+
"outDir": "dist",
|
|
32
|
+
"rootDir": "src",
|
|
33
|
+
},
|
|
34
|
+
"include": ["src/**/*"],
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Phase 2: Rename files (Week 1)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Renamed .js → .ts one directory at a time
|
|
42
|
+
# Started with utility files that had no dependencies
|
|
43
|
+
find src/utils -name "*.js" -exec bash -c 'mv "$0" "${0%.js}.ts"' {} \;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Phase 3: Add types gradually (Week 2-4)
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// Before: implicit any everywhere
|
|
50
|
+
function processUser(user) {
|
|
51
|
+
return { name: user.name, role: user.role || "viewer" };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// After: explicit types
|
|
55
|
+
interface User {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
role?: "admin" | "editor" | "viewer";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function processUser(user: User): { name: string; role: string } {
|
|
62
|
+
return { name: user.name, role: user.role ?? "viewer" };
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Phase 4: Enable strict mode (Week 5)
|
|
67
|
+
|
|
68
|
+
```jsonc
|
|
69
|
+
{
|
|
70
|
+
"compilerOptions": {
|
|
71
|
+
"strict": true,
|
|
72
|
+
"noUncheckedIndexedAccess": true,
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Results
|
|
78
|
+
|
|
79
|
+
- Runtime type errors: 12/month → 0/month
|
|
80
|
+
- Onboarding time: 3 weeks → 1 week
|
|
81
|
+
- Refactoring confidence: significantly improved with IDE support
|
|
82
|
+
|
|
83
|
+
## Learnings
|
|
84
|
+
|
|
85
|
+
- Incremental migration is key — never stop shipping features
|
|
86
|
+
- Start with leaf files (utilities), move inward to core logic
|
|
87
|
+
- `@ts-expect-error` is better than `any` for tracking tech debt
|
|
88
|
+
- Enable `strict` as soon as possible to avoid accumulating debt
|
|
89
|
+
- The build time increase was negligible (< 2 seconds)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knowledgine/cli",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,13 +14,22 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"@clack/prompts": "^1.1.0",
|
|
18
|
+
"boxen": "^8.0.1",
|
|
19
|
+
"chalk": "^5.6.2",
|
|
17
20
|
"chokidar": "^5.0.0",
|
|
21
|
+
"cli-table3": "^0.6.5",
|
|
18
22
|
"commander": "^14.0.3",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
23
|
+
"log-symbols": "^7.0.1",
|
|
24
|
+
"ora": "^9.3.0",
|
|
25
|
+
"smol-toml": "^1.6.0",
|
|
26
|
+
"@knowledgine/core": "0.2.1",
|
|
27
|
+
"@knowledgine/ingest": "0.2.1",
|
|
28
|
+
"@knowledgine/mcp-server": "0.2.1"
|
|
21
29
|
},
|
|
22
30
|
"files": [
|
|
23
|
-
"dist"
|
|
31
|
+
"dist",
|
|
32
|
+
"fixtures"
|
|
24
33
|
],
|
|
25
34
|
"description": "CLI for indexing markdown files and serving MCP knowledge tools",
|
|
26
35
|
"mcpName": "io.github.3062-in-zamud/knowledgine",
|