Skip to content

Commit 823623f

Browse files
committed
doc: add protocol-split design doc
1 parent e101011 commit 823623f

2 files changed

Lines changed: 254 additions & 0 deletions

File tree

docs/dev/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
| [File Index](./file-index.md) | Key files quick reference |
1313
| [Testing Guide](./testing.md) | Rust + Lua + Docker SQL testing |
1414
| [Refactoring Plan](./refactoring-plan.md) | F1–F8 architecture debt, phased remediation plan |
15+
| [Protocol Split Design](./protocol-split-design.md) | HTTP ↔ SQL repo split proposal |
1516
| [Archived Docs](./archived/README.md) | Outdated design documents |
1617

1718
## HTTP

docs/dev/protocol-split-design.md

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
# Protocol Split Design: HTTP ↔ SQL
2+
3+
> Splitting the current monorepo into two independent projects — `poste.nvim` (HTTP + Redis) and `poste-sql.nvim`.
4+
>
5+
> Status: **Proposal** · Last updated: 2026-07-21
6+
7+
---
8+
9+
## Motivation
10+
11+
HTTP and SQL share little commonality at the feature level. Keeping them in one repo creates friction:
12+
13+
1. **Shared-file coupling**`lua/poste/init.lua` unconditionally loads SQL during `setup()`, even for HTTP-only users
14+
2. **Dispatch entanglement**`buffer_setup.lua`, `indicators.lua`, and help windows must understand both protocols
15+
3. **Uneven release cycles** — HTTP evolves faster than SQL; bundling them forces SQL users to take HTTP changes and vice versa
16+
4. **Cognitive overhead** — contributors must understand the full project to modify shared files
17+
5. **Plugin load cost** — SQL modules (~20+ files) load on every Neovim startup even if user never opens `.sql`
18+
19+
---
20+
21+
## Current Architecture
22+
23+
```
24+
poste/ # Single repo
25+
├── lua/poste/
26+
│ ├── init.lua ← Coupled: loads HTTP + SQL unconditionally
27+
│ ├── state.lua ← Shared: keymaps, config, M.sql namespace
28+
│ ├── buffer_setup.lua ← Coupled: dispatches to SQL via filetype check
29+
│ ├── indicators.lua ← Shared: imports poste.http.cache (reverse coupling)
30+
│ ├── select.lua ← Shared: generic picker
31+
│ ├── help.lua ← Coupled: shows HTTP and SQL keymaps together
32+
│ ├── constants.lua ← Shared
33+
│ ├── util.lua ← Shared
34+
│ ├── install.lua ← Shared
35+
│ ├── cli.lua ← Shared
36+
│ ├── http/ ← HTTP protocol Lua
37+
│ └── sql/ ← SQL protocol Lua
38+
├── crates/
39+
│ ├── poste-core/ ← Shared: Protocol enum, parser, request.rs
40+
│ ├── poste-exec/ ← Shared: executor.rs + sql_executor/
41+
│ └── poste-cli/ ← Shared: single binary
42+
├── ftdetect/poste.vim ← Coupled: .http + .redis + .sql + .sqlite
43+
├── syntax/ ← Split: poste_http.vim + poste_sql.vim (already separate)
44+
└── plugin/poste.lua ← Shared: calls require("poste").setup()
45+
```
46+
47+
### Specific coupling points
48+
49+
| Point | File | Problem |
50+
|-------|------|---------|
51+
| CP1 | `lua/poste/init.lua:55` | `require("poste.sql.init").setup(opts)` — always loads SQL |
52+
| CP2 | `lua/poste/init.lua:175-225` | Single autocmd block handles `.http`, `.redis`, `.sql`, `.sqlite` |
53+
| CP3 | `lua/poste/buffer_setup.lua:35-40` | `goto_definition` keymap checks filetype and dispatches to SQL |
54+
| CP4 | `lua/poste/indicators.lua:86` | `require("poste.http.cache")` — shared module depends on HTTP |
55+
| CP5 | `lua/poste/help.lua` | Single help window shows both HTTP and SQL keymaps |
56+
| CP6 | `lua/poste/state.lua:222-241` | `M.sql` namespace lives in shared state file |
57+
| CP7 | `lua/poste/http/run.lua:533-536` | HTTP run module imports SQL init |
58+
| CP8 | `crates/poste-exec/src/executor.rs` | Single dispatch routes to HTTP, Redis, and SQL |
59+
| CP9 | `crates/poste-cli/src/run.rs` | Single `execute()` function handles all protocols |
60+
| CP10 | `crates/poste-core/src/request.rs` | `Protocol` enum unifies all protocols in one type |
61+
| CP11 | `ftdetect/poste.vim` | Single file sets filetypes for all protocols |
62+
63+
---
64+
65+
## Target Architecture
66+
67+
### Option A: Core + SQL Plugin (Recommended)
68+
69+
```
70+
poste.nvim (monorepo) poste-sql.nvim (separate repo)
71+
├── lua/poste/ ├── lua/poste/sql/
72+
│ ├── init.lua │ ├── init.lua (was poste.sql.init)
73+
│ ├── state.lua │ ├── buffer.lua
74+
│ ├── constants.lua │ ├── completion.lua
75+
│ ├── select.lua │ ├── context.lua
76+
│ ├── indicators.lua │ ├── connections.lua
77+
│ ├── buffer_setup.lua │ ├── db_browser/
78+
│ ├── util.lua │ ├── export.lua
79+
│ ├── install.lua │ ├── format.lua
80+
│ ├── cli.lua │ ├── editor.lua
81+
│ ├── help.lua │ ├── import.lua
82+
│ ├── error.lua │ ├── introspect.lua
83+
│ └── http/ │ ├── statement.lua
84+
│ ├── init.lua │ ├── syntax.lua
85+
│ ├── run.lua │ └── ...
86+
│ ├── format.lua ├── ftdetect/ (.sql only)
87+
│ └── ... ├── syntax/ (poste_sql.vim)
88+
├── ftdetect/ (.http/.redis) ├── plugin/poste-sql.lua
89+
├── syntax/ (poste_http.vim) └── depends: poste.nvim (shared infra + binary)
90+
├── plugin/poste.lua
91+
└── crates/ (unchanged)
92+
├── poste-core/
93+
├── poste-exec/
94+
└── poste-cli/
95+
```
96+
97+
**Key design decisions:**
98+
99+
1. **Rust binary stays monolithic**`poste` binary compiles all protocols. SQL plugin users just need the same binary. Splitting Rust would mean duplicating `poste-core` and maintaining two CI pipelines for negligible gain.
100+
101+
2. **Shared Lua stays in `poste.nvim`**`state.lua`, `select.lua`, `indicators.lua`, `util.lua`, `cli.lua`, `install.lua`, `constants.lua`, `error.lua` are genuinely protocol-neutral. SQL plugin depends on them.
102+
103+
3. **SQL plugin uses `require("poste.*")` paths** — no path aliasing needed. The `poste.nvim` plugin must be on `rtp` for SQL plugin to work.
104+
105+
4. **`poste-sql.nvim` only ships `lua/poste/sql/`** — its `plugin/poste-sql.lua` calls `require("poste.sql.init").setup()` which is now moved from `poste.nvim` to `poste-sql.nvim`.
106+
107+
### Option B: Two Independent Plugins (Alternative)
108+
109+
Each plugin duplicates shared Lua code. Appropriate if zero external dependency is critical.
110+
111+
```
112+
poste-http.nvim poste-sql.nvim
113+
├── lua/poste/ ├── lua/poste/
114+
│ ├── init.lua │ ├── init.lua
115+
│ ├── state.lua (copy) │ ├── state.lua (copy)
116+
│ ├── constants.lua (copy) │ ├── constants.lua (copy)
117+
│ ├── select.lua (copy) │ ├── select.lua (copy)
118+
│ ├── indicators.lua (copy) │ ├── indicators.lua (copy)
119+
│ ├── util.lua (copy) │ ├── util.lua (copy)
120+
│ ├── install.lua (copy) │ ├── install.lua (copy)
121+
│ ├── cli.lua (copy) │ ├── cli.lua (copy)
122+
│ ├── help.lua (copy) │ ├── help.lua (copy)
123+
│ ├── error.lua (copy) │ ├── error.lua (copy)
124+
│ └── http/ │ └── sql/
125+
├── ftdetect/ ├── ftdetect/
126+
├── syntax/ ├── syntax/
127+
├── plugin/poste.lua ├── plugin/poste.lua
128+
└── crates/ (same binary) └── crates/ (same binary)
129+
```
130+
131+
**Not recommended**~10 shared files duplicated, drift inevitable.
132+
133+
---
134+
135+
## Migration Plan
136+
137+
### Phase 1: Decouple (within current repo)
138+
139+
Remove all cross-coupling between HTTP and SQL code without changing the repo structure.
140+
141+
| Step | File | Change |
142+
|------|------|--------|
143+
| D1 | `lua/poste/init.lua` | Remove `require("poste.sql.init").setup(opts)`. SQL sets up its own autocmds via `plugin/poste-sql.lua` |
144+
| D2 | `lua/poste/init.lua:175-225` | Split autocmd: `.sql`/`.sqlite` handled by SQL plugin's `ftdetect/` + `plugin/` |
145+
| D3 | `lua/poste/buffer_setup.lua:35-40` | Remove SQL dispatch from `goto_definition`. SQL plugin installs its own keymap |
146+
| D4 | `lua/poste/indicators.lua:86` | Remove `require("poste.http.cache")`. Move that logic into HTTP-specific path |
147+
| D5 | `lua/poste/help.lua` | Split into `http/help.lua` and `sql/help.lua`. Shared help shows only what's installed |
148+
| D6 | `lua/poste/state.lua:222-241` | Move `M.sql` namespace into `lua/poste/sql/state.lua` (loaded by SQL plugin) |
149+
| D7 | `lua/poste/http/run.lua:533-536` | Remove SQL delegation. SQL plugin handles its own `run_request` |
150+
| D8 | `ftdetect/poste.vim` | Remove `.sql`/`.sqlite` entries. Handled by SQL plugin's own `ftdetect/` |
151+
152+
After D1–D8, `poste.nvim` loads **zero** SQL modules. SQL modules only load when user opens a `.sql` file and SQL plugin is installed.
153+
154+
### Phase 2: Extract SQL Repo
155+
156+
1. Create `poste-sql.nvim` repo with `lua/poste/sql/` subtree
157+
2. Add `plugin/poste-sql.lua`:
158+
159+
```lua
160+
-- plugin/poste-sql.lua
161+
-- Only activates if poste.nvim (core) is installed
162+
local ok, _ = pcall(require, "poste.state")
163+
if not ok then
164+
vim.notify("poste-sql.nvim requires poste.nvim", vim.log.levels.WARN)
165+
return
166+
end
167+
require("poste.sql.init").setup()
168+
```
169+
170+
3. Add `ftdetect/poste_sql.vim`:
171+
172+
```vim
173+
au BufRead,BufNewFile *.sql setfiletype poste_sql
174+
au BufRead,BufNewFile *.sqlite setfiletype poste_sqlite
175+
```
176+
177+
4. Add `syntax/poste_sql.vim` and `syntax/poste_dataset.vim` (already separate files)
178+
5. Remove `lua/poste/sql/` from `poste.nvim` repo
179+
6. Remove `.sql`/`.sqlite` from `poste.nvim`'s `ftdetect/poste.vim`
180+
181+
### Phase 3: Shared Infra Cleanup
182+
183+
After the split, prune `poste.nvim`:
184+
185+
- `state.lua` — remove `M.sql` namespace, remove SQL keymap sections
186+
- `init.lua` — remove `poste_sql`/`poste_sqlite` from `poste_status()` check
187+
- `help.lua` — show only HTTP + Redis keymaps
188+
- `buffer_setup.lua` — remove SQL filetype dispatch
189+
190+
---
191+
192+
## Rust Side: No Split
193+
194+
The Rust binary stays monolithic for these reasons:
195+
196+
1. **Dependency graph is already clean**`sql_executor/` is a separate module, zero imports from `executor.rs`
197+
2. **No compile-time conflict** — sqlx and curl-rust coexist without issues
198+
3. **CI cost** — one binary = one compile, one release artifact
199+
4. **User experience** — both plugins use `:PosteUpdate` to get the same binary
200+
201+
The only Rust change needed: ensure `poste run` doesn't require SQL libraries when running HTTP requests (it already doesn't — dispatch is purely based on `Protocol` enum).
202+
203+
---
204+
205+
## Impact Analysis
206+
207+
### What breaks
208+
209+
| User scenario | Impact | Mitigation |
210+
|---------------|--------|------------|
211+
| Has both `.http` and `.sql` files | Must install both plugins | Clear README, single install command via lazy.nvim spec |
212+
| Uses `require("poste.sql.*")` in custom scripts | Works if SQL plugin is installed | Error message if missing |
213+
| Autocmds referencing `poste_sql` filetype | Unaffected | Filetype registration moved to SQL plugin |
214+
| CI / test scripts | `tests/run.sh` must cover both repos | Each repo has its own tests |
215+
216+
### What improves
217+
218+
| Metric | Before | After |
219+
|--------|--------|-------|
220+
| Plugin load time (HTTP-only user) | Loads ~20 SQL modules | Zero SQL modules |
221+
| Plugin load time (SQL-only user) | Loads ~30 HTTP modules | Zero HTTP modules |
222+
| Shared-file touch conflicts | `init.lua` changed by both | Each repo owns its `init.lua` |
223+
| Release cycle | Lockstep | Independent |
224+
| New contributor onboarding | Must understand all protocols | Only needs to understand one |
225+
226+
### Compat scenarios
227+
228+
Users who want both install:
229+
230+
```lua
231+
-- lazy.nvim
232+
{
233+
"beyondlex/poste.nvim",
234+
opts = {},
235+
dependencies = {
236+
"beyondlex/poste-sql.nvim", -- optional
237+
},
238+
}
239+
```
240+
241+
---
242+
243+
## Related Documents
244+
245+
- [Architecture Overview](./architecture-overview.md) — current layered architecture
246+
- [Refactoring Plan](./refactoring-plan.md) — F1-F8 architecture debt remediation
247+
- [HTTP Dev Docs](./http/README.md)
248+
- [SQL Dev Docs](./sql/README.md)
249+
- [File Index](./file-index.md)
250+
251+
---
252+
253+
*Protocol split design — Last updated: 2026-07-21*

0 commit comments

Comments
 (0)