Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ ENCRYPTION_KEY=
# whose username and bcrypt password hash are supplied via env. There
# is no users table; rotating the credential means redeploying with a
# new ADMIN_PASSWORD_HASH.
# Generate the hash with:
# python -c "from app.auth.hashing import hash_password; print(hash_password('your-password'))"
# Generate the hash from backend/ with its environment activated. The prompt
# keeps the real password out of this file and your shell history:
# python -c "from getpass import getpass; from app.auth.hashing import hash_password; print(hash_password(getpass('Admin password: ')))"
ADMIN_USERNAME=
ADMIN_PASSWORD_HASH=

Expand Down
11 changes: 10 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ These instructions apply repository-wide. Prefer local instructions under `.gith
- Use PyJWT + bcrypt for auth.
- Use structlog structured logging.
- Use Vite + React SPA for frontend.
- Include rich SQL editor in wizard flows (Monaco or CodeMirror 6).
- Preserve the existing CodeMirror 6 SQL editor in endpoint wizard flows.

## Build and Test Commands
- Backend setup: `cd backend && python -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt`.
Expand All @@ -33,6 +33,13 @@ These instructions apply repository-wide. Prefer local instructions under `.gith
## Mandatory Safety Rules
- SQL must be parameterized with bind params only (`:param_name`).
- Never generate SQL using string concatenation from user input.
- Treat bind markers inside single-quoted SQL literals as text, not parameters.
- Enforce required parameters for both live and snapshot HTTP requests, even when endpoint
defaults exist.
- Keep scheduler bindings independent from endpoint request defaults. Every scheduled bind must
use a validated declarative schedule source.
- Never serve a parameterized snapshot without complete cached-column mappings, coverage
validation, and typed row filtering. Snapshot filters do not provide tenant authorization.
- Never store secrets in code, tests, fixtures, or docs.
- Never break existing `/api/v1/*` contracts without version bump + migration notes.
- Never change an applied Alembic revision; add a new revision.
Expand All @@ -43,6 +50,8 @@ These instructions apply repository-wide. Prefer local instructions under `.gith
- Include docs updates for API/config/workflow changes.
- Keep changes minimal and scoped to request.
- Explain risks when touching auth, SQL execution, migrations, or scheduler logic.
- Update `docs/scheduler_parameter_bindings.md` whenever the endpoint, schedule, or snapshot
parameter contract changes.

## Stop Conditions
- If API contract is unclear, inspect existing `/api/v1` routers and docs.
Expand Down
10 changes: 10 additions & 0 deletions .github/instructions/backend.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@
- Emit structlog events with required fields.
- Validate SQL bind parameters via typed schemas before execution.
- Use SQLAlchemy `text()` and binds for user SQL.
- Enforce required HTTP parameters with `build_param_model(..., enforce_required=True)` for both
live and snapshot data paths.
- Resolve scheduled SQL binds only from schedule-owned declarative bindings.
- Require complete snapshot filter mappings, prove retained-run coverage, and filter cached rows
with the declared typed `eq`/`gte`/`lte` operators.

## Do Not
- Do not add unversioned API routes.
- Do not use `python-jose` or `passlib`.
- Do not interpolate SQL strings with user input.
- Do not treat quoted `':param'` text as a bind placeholder.
- Do not reuse endpoint defaults as implicit schedule inputs or serve an unfiltered parameterized
snapshot.
- Do not edit old migration revisions after merge.
- Do not return secrets in API responses or logs.

Expand All @@ -36,6 +44,8 @@
- `endpoint`
- `status`
- `duration_ms`
- `method`
- `client_ip`
- `event`

## Stop Conditions
Expand Down
10 changes: 6 additions & 4 deletions .github/instructions/docker.instructions.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Docker Instructions

## Do
- Keep Docker assets in `docker/` and `docker-compose.yml`.
- Ensure compose supports `api`, `web`, `db` services.
- Keep Docker assets in `docker/`, `docker-compose.yml`, and `compose.production.yml`.
- Ensure compose supports `db`, one-shot `migrate`, `api`, and `web` services.
- Keep optional local Oracle service/profile isolated and documented.
- Use deterministic base image tags.
- Ensure backend and frontend images build in CI.
Expand All @@ -21,8 +21,10 @@
- `docker compose logs --tail=200 db`

## Runtime Expectations
- Backend starts only after DB readiness.
- Migrations are documented and run deterministically.
- The `migrate` service starts after DB readiness and must complete successfully before the API
starts.
- Migrations are applied deterministically with `alembic upgrade head`; do not add an independent
API-startup migration path that can race the Compose service.
- Config comes from environment variables compatible with Pydantic Settings.

## Stop Conditions
Expand Down
7 changes: 6 additions & 1 deletion .github/instructions/frontend.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
- Use React + TypeScript + Tailwind + shadcn/ui.
- Keep API clients aligned to `/api/v1/admin/*` and `/api/v1/data/*`.
- Implement wizard UX for Module 2 with a rich SQL editor.
- Use Monaco (`@monaco-editor/react`) or CodeMirror 6 (`@uiw/react-codemirror`) for SQL authoring.
- Use the existing CodeMirror 6 integration (`@uiw/react-codemirror`) for SQL authoring.
- Provide explicit validation errors for bind params and auth setup.
- Keep preview samples separate from persisted endpoint defaults and schedule bindings.
- For snapshot endpoints, require a cached output column and `eq`/`gte`/`lte` operator for every
request parameter in create and edit flows.
- Write component tests for wizard steps and critical forms.

## Do Not
Expand All @@ -26,6 +29,8 @@
- Wizard must enforce bind variable awareness (`:param_name`).
- Endpoint creation UI must expose auth assignment and data strategy selection.
- Show clear status for live-query vs scheduled-snapshot behavior.
- Explain that schedule bindings control what Oracle loads, while snapshot filter mappings control
which cached rows an authenticated data request returns; neither replaces authentication.
- Surface backend validation errors verbatim when safe.

## Stop Conditions
Expand Down
7 changes: 7 additions & 0 deletions .github/instructions/testing.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@
- SQL bind parameter validation and rejection of unsafe SQL composition.
- Dynamic route resolution under `/api/v1/data/*`.
- Scheduler job creation/execution logging and snapshot cache behavior.
- Required-parameter enforcement for both live and snapshot requests, including supported date
formats and optional SQL `NULL` behavior.
- Schedule binding completeness, logical-date/window resolution, retained-snapshot coverage,
reversed ranges, mapped-column failures, and typed cached-row filtering.
- Alembic migration upgrade/downgrade sanity.

## Frontend Test Focus
Comment thread
badry-dev marked this conversation as resolved.

- Wizard step transitions and validation.
- SQL editor integration behavior and parameter UX.
- Separation of preview samples, endpoint defaults, schedule bindings, and snapshot filter
mappings in endpoint create/edit flows.
- Connection/auth/schedule/settings form validation.
- Error rendering for API failures.

Expand Down
35 changes: 35 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,39 @@ Build and maintain a secure, testable monorepo for dynamic SQL-to-API exposure w
- Parameter mapping source: validated request inputs -> typed schema -> bind dict.
- Reject queries containing interpolated values from raw strings.
- Execute user SQL through SQLAlchemy Core `text()` with bound params.
- Bind markers inside single-quoted SQL literals are text, not parameters; never quote a bind
placeholder (use `column = :value`, not `column = ':value'`).

## Parameter Ownership Contract

- SQL preview values are temporary samples only; they are never persisted as endpoint or schedule
defaults.
- Live and snapshot HTTP requests enforce every descriptor marked `required`, even when the
endpoint descriptor contains a default.
- Optional live-request parameters may use a typed literal default, explicit SQL `NULL`, or the
supported dynamic date defaults `today` and `yesterday`.
- Scheduled snapshot execution never reads endpoint defaults. Every SQL bind is owned by the
schedule through exactly one validated binding source: `literal`, `null`, `run_date`,
`relative_date`, `window_start`, or `window_end`.
- Date inputs accept `YYYY-MM-DD` and `DD-MM-YYYY`. Schedule calendar math is evaluated from the
persisted nominal run time in the schedule's IANA timezone.

## Snapshot Request Contract

- Every parameterized snapshot endpoint must map every request parameter to a cached output
column and one operator: `eq`, `gte`, or `lte`.
- Mappings target the final cached column name after `column_map` renaming. They filter rows; they
are not tenant authorization. Authentication remains mandatory and independent.
- Select the newest retained snapshot whose persisted resolved schedule parameters cover the
request, then apply typed row filtering. Never return an unfiltered parameterized snapshot.
- Missing/invalid required parameters, reversed ranges, incomplete mappings, unavailable mapped
columns, and out-of-coverage requests return explicit HTTP 422 responses. No retained snapshot
returns HTTP 503; an in-coverage request with no matching rows returns HTTP 200 with `data: []`.
- `null_means_all` is valid only for an optional `eq` mapping and means a scheduled SQL `NULL`
covers every requested value for that parameter.
- Snapshot mappings are stored in the existing endpoint parameter JSON and do not require a
relational migration. Schedule-owned bindings and logical-run audit fields are relational and
are covered by Alembic revision `e4a6c2d9f801`.

## Required Log Fields
- `request_id`
Expand All @@ -52,6 +85,8 @@ Build and maintain a secure, testable monorepo for dynamic SQL-to-API exposure w
- Run formatting/lint/tests for changed areas.
- Add/update Alembic migration when schema changed.
- Update docs when contracts, settings, or workflows changed.
- Keep `README.md`, `docs/architecture.md`, `docs/scheduler_parameter_bindings.md`, and relevant
agent instructions aligned when parameter or snapshot behavior changes.
- Verify no secrets/tokens/credentials are committed.

## Stop Conditions
Expand Down
5 changes: 5 additions & 0 deletions AI_WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
4. If API changes: preserve `/api/v1/*` compatibility or add version bump.
5. After editing: run lint/tests/build for touched areas.
6. Update docs/changelog notes when behavior or contract changes.
7. For parameter behavior, keep preview samples, endpoint request defaults, schedule bindings,
and snapshot request filters separate; verify the canonical contract in
`docs/scheduler_parameter_bindings.md`.

## Verification Checklist
- Backend checks pass: `ruff`, `mypy`, `pytest`.
Expand All @@ -26,6 +29,8 @@
- Migrations included for DB changes.
- No secrets in code, logs, tests, or docs.
- No breaking API change without explicit versioning plan.
- Required live/snapshot parameters remain enforced and parameterized snapshots cannot fall back
to unfiltered cached data.

## PR Checklist
- Scope is clear and minimal.
Expand Down
33 changes: 28 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ QueryGateway is a monorepo for creating secure, dynamic REST endpoints from Orac
- Python 3.14+, FastAPI, Pydantic Settings v2.
- PostgreSQL app DB, SQLAlchemy 2.0, Alembic.
- Oracle connectivity via `python-oracledb`.
- APScheduler 3.x with persistent PostgreSQL job store.
- APScheduler 3.x with an in-memory job store; schedule definitions are persisted in PostgreSQL
and active jobs are restored on API startup.
- Auth: `PyJWT` + `bcrypt`.
- Logging: `logging` + `structlog`.
- Frontend: Vite + React SPA + TypeScript + shadcn/ui + Tailwind.
- Module 2 requires rich SQL editor: Monaco (`@monaco-editor/react`) or CodeMirror 6 (`@uiw/react-codemirror`).
- The endpoint wizard uses CodeMirror 6 through `@uiw/react-codemirror` for SQL authoring.

## Repo Map
- `backend/`: API, models, migrations, scheduler, auth, SQL execution.
Expand Down Expand Up @@ -45,21 +46,43 @@ QueryGateway is a monorepo for creating secure, dynamic REST endpoints from Orac
- Validate and coerce params with typed schemas before execution.
- Use SQLAlchemy `text()` + bind dict.
- Never concatenate request values into SQL strings.
- Bind markers inside single-quoted SQL literals are not parameters and must not be used.

## Endpoint and Scheduler Parameter Conventions

- Preview inputs are temporary samples and are not persisted.
- Every required HTTP parameter remains required for live and snapshot requests, regardless of
configured endpoint defaults.
- Endpoint defaults apply to omitted optional live requests only. Schedules own every SQL bind
through `literal`, `null`, `run_date`, `relative_date`, `window_start`, or `window_end`.
- Parameterized snapshot endpoints map every request parameter to a post-rename cached column via
`eq`, `gte`, or `lte`. Coverage is checked against persisted job-run parameters before cached
rows are filtered.
- Snapshot filter mappings select data; they never replace endpoint authentication or authorize a
tenant.
- The full contract and stable error codes are documented in
`docs/scheduler_parameter_bindings.md`.

## Logging Conventions

- Use structured logging everywhere.
- Mandatory fields: `request_id`, `user`, `endpoint`, `status`, `duration_ms`, `event`.
- Mandatory fields: `request_id`, `user`, `endpoint`, `status`, `duration_ms`, `method`,
`client_ip`, `event`.
- Add scheduler fields for jobs: `job_id`, `run_id`, `row_count`, `success`.

## Run Commands (Expected)
- Backend setup: `cd backend && python -m venv .venv && . .venv/bin/activate` (Windows: `.venv\Scripts\activate`) then `pip install -r requirements.txt`.

- Backend setup: `cd backend && python3.14 -m venv .venv && . .venv/bin/activate`
(Windows: `py -3.14 -m venv .venv`, then `.venv\Scripts\activate`) and install
`requirements.txt`.
- Backend dev: `cd backend && uvicorn app.main:app --reload`.
- Backend checks: `cd backend && ruff check . && mypy . && pytest`.
- Frontend setup: `cd frontend && npm install`.
- Frontend dev: `cd frontend && npm run dev`.
- Frontend checks: `cd frontend && npm run eslint && npm run prettier:check && npm run test`.
- Docker build: `docker compose build`.
- Docker run: `docker compose up -d`.
- Docker run: `docker compose up -d --build` (the one-shot `migrate` service must complete before
the API starts).

## Working Protocol
- Before edits: summarize target files and planned commands.
Expand Down
Loading