54 lines
2.7 KiB
Markdown
54 lines
2.7 KiB
Markdown
# Story: Admin Page to Add / Remove Git Sources
|
||
|
||
**Phase:** `35_git_sources_admin` · **E2E:** `tests/e2e/test_git_sources_admin.py`
|
||
|
||
## Narrative
|
||
|
||
As **the admin (owner)**, today I manage the git repos that feed the
|
||
knowledge base by editing `BOR_GIT_SOURCES` in `.env` and restarting. I
|
||
want a page only I can access where I can **add and remove git
|
||
sources** — no env file, no restart — and have the Sync button
|
||
(phase 32) and `import_docs` (phase 28) use that stored list.
|
||
|
||
- **Given** I am signed in as admin
|
||
- **When** I open the Git sources page and add a repo URL (or remove
|
||
one)
|
||
- **Then** the change is stored in Postgres (`git_sources` table) and
|
||
the next sync / import uses the stored list — the
|
||
`BOR_GIT_SOURCES` env var remains only a fallback while the table is
|
||
empty, and phase 32's fail-loud "no git sources configured" is
|
||
preserved when both are empty.
|
||
|
||
## Acceptance criteria
|
||
1. Migration 0006: `git_sources` (id UUID PK, url TEXT UNIQUE NOT
|
||
NULL, added_at TIMESTAMPTZ) — reversible, integration-tested
|
||
up/down (existing migration-test pattern).
|
||
2. Admin-only API (phase 16 pattern — 403 `admin only` anonymous):
|
||
`GET /api/git-sources` (DB rows in added order; while the table is
|
||
empty, the env list with `from_env: true`), `POST /api/git-sources`
|
||
{url} (trimmed, 1–500 chars, `https?://` / `ssh://` / `git@`
|
||
shape, 409 on duplicate with a detail that never echoes the URL),
|
||
`DELETE /api/git-sources/{id}` (204 / 404).
|
||
3. `effective_git_sources()` shared by `app/api/sync.py::_run_sync`
|
||
and `scripts/import_docs.py`: DB rows win, env fallback only while
|
||
the table is empty, fail-loud unchanged when both are empty; the
|
||
sync log line records the list origin (`origin=db|env`).
|
||
4. `/git-sources.html` — soft-gated like the Sources page (anonymous:
|
||
sign-in gate) with the standard header (phase 34) and an
|
||
admin-only "Git sources" nav link on all five pages (phase 29
|
||
pattern): sources list (mono URL + added date + per-row Remove),
|
||
an add form (labeled input + Add, inline error, never-stale button
|
||
per §7.4), an env-fallback note while the table is empty, and a
|
||
hint that the KB itself updates via the Sync button.
|
||
5. `.env.example` + README: `BOR_GIT_SOURCES` documented as the
|
||
empty-table fallback; the admin page is the primary management UI.
|
||
6. Unit + integration green, `app/` coverage >90%, story E2E green in
|
||
isolation, ruff + pyright clean, one `--no-gpg-sign` commit.
|
||
|
||
## Playwright Mapping Rule
|
||
`tests/e2e/test_git_sources_admin.py` — one story, one file, run in
|
||
isolation: anonymous gets the sign-in gate (and 403s on the API); the
|
||
admin adds/removes sources on the page (the list updates live, invalid
|
||
input gets an inline error) and reaches the page via the "Git
|
||
sources" nav link on every page.
|