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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,6 @@ Thumbs.db
*.nt
!tests/fixtures/*.ttl
!tests/fixtures/*.owl

# Local git worktrees
.worktrees/
2 changes: 2 additions & 0 deletions .serena/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/cache
/project.local.yml
53 changes: 53 additions & 0 deletions .serena/memories/code_style_and_conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Code Style & Conventions — ontokit-api

## Formatting
- **Line length**: 100 characters
- **Formatter**: `ruff format` (enforced by pre-commit)
- **Target**: Python 3.11

## Linting (ruff)
Selected rule sets:
- `E`, `W` — pycodestyle errors/warnings
- `F` — Pyflakes
- `I` — isort (`known-first-party = ["ontokit"]`)
- `B` — flake8-bugbear
- `C4` — flake8-comprehensions
- `UP` — pyupgrade
- `ARG` — flake8-unused-arguments
- `SIM` — flake8-simplify

Ignored: `E501` (line length handled by formatter, not linter).

## Type checking
- **mypy** in **strict mode** (`strict = true`)
- `warn_return_any = true`, `warn_unused_ignores = true`
- Plugin: `pydantic.mypy`
- Pyright also configured (uses `.venv`, py 3.11)

## Pydantic conventions
- Pydantic v2 (>=2.13.3, <2.14)
- `init_forbid_extra = true`, `init_typed = true`
- Strict validation everywhere, computed fields where appropriate

## Architectural patterns
- **Async-first**: all I/O uses async/await
- **Dependency injection**: FastAPI's `Depends()`
- **Service singletons**: obtained via `get_service_name()` dependency providers
- **UTC-aware datetimes** throughout (no naive datetimes)
- **Layered**: routes → services → models / schemas / core

## URL versioning
The `/api/v1/` prefix is set in `main.py` router registration — do NOT recreate the version in the directory tree.

## Git module guideline
Use `ontokit/git/bare_repository.py` (pygit2-based) for new code.
The GitPython-based `repository.py` is **deprecated** and kept only for backward compat.

## Pre-commit
Enabled hooks: ruff (lint + format) and mypy. Installed via `make setup`.

## Testing conventions
- Pytest with `asyncio_mode = "auto"` (no need for `@pytest.mark.asyncio`)
- `testpaths = ["tests"]`
- Default args: `-v --cov=ontokit --cov-report=term-missing`
- Layout: `tests/unit/` and `tests/integration/`
31 changes: 31 additions & 0 deletions .serena/memories/project_overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# OntoKit API — Project Overview

Collaborative OWL ontology curation API built with **FastAPI** (Python 3.11+, target 3.13). Distributed as the `ontokit` package on PyPI.

## Purpose
Provides a RESTful API for managing ontologies, semantic web knowledge graphs, and team collaboration with git-based version control. Sister project to `ontokit-web` (frontend).

## Core Capabilities
- REST endpoints for ontologies, classes, properties, individuals
- Project management (public/private visibility, member roles)
- Git-based version control with branches + PR workflow (pygit2 bare repos for concurrent access)
- 20+ ontology linting/validation rules
- Semantic search via `sentence-transformers` + `pgvector`
- Real-time collaboration over WebSockets
- Background job queue (ARQ + Redis)
- GitHub App integration for syncing remote repos

## Tech Stack
- **Framework**: FastAPI, async-first
- **Database**: PostgreSQL 17 + SQLAlchemy 2.0 (async via asyncpg) + Alembic migrations
- **Cache/Queue**: Redis 7 + ARQ
- **Object Storage**: MinIO (S3-compatible)
- **Auth**: Zitadel (OIDC/OAuth2, JWT validation)
- **RDF**: RDFLib 7.1+, OWLReady2
- **Git**: pygit2 (bare repos); legacy GitPython implementation deprecated
- **Validation**: Pydantic v2 (strict mode)
- **Package Mgmt**: uv

## Repo Location

Companion repos in same parent directory: `ontokit-web` (frontend), `folio-api`, `ontokit-api.wiki`.
55 changes: 55 additions & 0 deletions .serena/memories/project_structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Codebase Structure — ontokit-api

## Top-level layout
```text
ontokit-api/
├── ontokit/ # main package
├── tests/ # unit + integration tests
├── alembic/ # DB migrations
├── scripts/ # release, migration, setup scripts
├── data/ # data assets
├── docs/ # documentation
├── config/ # config files
├── compose.yaml # docker compose (dev)
├── compose.prod.yaml # docker compose (prod infra)
├── Dockerfile / Dockerfile.prod
├── pyproject.toml / uv.lock
├── alembic.ini
├── Makefile
├── .env.example
├── CLAUDE.md, AGENTS.md, GEMINI.md, README.md, SECURITY.md, RELEASING.md
```

## ontokit/ package layout (layered architecture)
```text
ontokit/
├── api/routes/ # REST endpoints (FastAPI routers)
├── services/ # Business logic layer
├── models/ # SQLAlchemy ORM models
├── schemas/ # Pydantic v2 request/response schemas
├── core/ # Config, database, auth infrastructure
├── git/ # Git repository management (bare repos via pygit2)
├── collab/ # WebSocket real-time collaboration
├── version.py # Version mgmt (Weblate-style, with -dev/-rc suffix support)
├── runner.py # CLI entry point (`ontokit` script)
├── worker.py # ARQ background job worker
└── main.py # FastAPI app + router registration
```

URL prefix `/api/v1/` is registered in `main.py`, NOT in directory structure.

## Key services (ontokit/services/)
- **ontology.py** — RDF/OWL graph operations (RDFLib + OWLReady2)
- **linter.py** — 20+ ontology validation rules
- **pull_request_service.py** — git-based PR workflow with diff generation
- **github_service.py** — GitHub App integration for remote sync
- **project_service.py** — project CRUD + member management

## Git module (ontokit/git/)
- **bare_repository.py** — `BareOntologyRepository` + `BareGitRepositoryService`; pygit2-based, no working dir, supports concurrent multi-user branch work
- **repository.py** — Legacy GitPython implementation (DEPRECATED)

## Tests
- `tests/unit/` — unit tests
- `tests/integration/` — integration tests
- `tests/conftest.py` — shared fixtures
82 changes: 82 additions & 0 deletions .serena/memories/suggested_commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Suggested Commands — ontokit-api

## First-time setup
```bash
make setup # uv sync --extra dev + pre-commit install
cp .env.example .env # then edit .env
./scripts/setup-zitadel.sh --update-env # provision Zitadel OIDC apps
```

## Dev server
```bash
uvicorn ontokit.main:app --reload
ontokit --reload # equivalent CLI (installed entry point)
```

## Docker (full stack)
```bash
docker compose up -d # full local stack
docker compose -f compose.prod.yaml up -d # infra only (hybrid mode)
docker compose exec api alembic upgrade head # migrate inside container
docker compose up -d --force-recreate api worker # restart after .env change
```

## Linting / Formatting / Type checking
```bash
make lint # uv run ruff check ontokit/ tests/ --fix
make format # uv run ruff format ontokit/ tests/
make typecheck # uv run mypy ontokit/

# raw equivalents:
ruff check ontokit/ --fix
ruff format ontokit/
mypy ontokit/
```

## Tests
```bash
make test # full suite w/ coverage
pytest tests/ -v --cov=ontokit # explicit
pytest tests/unit/test_health.py -v # single file
pytest tests/ -k "test_name" -v # by keyword
```

## Security scan (Semgrep)
With Pro:
```bash
semgrep --pro --config p/default --config p/owasp-top-ten --config p/python --config p/fastapi --config p/jwt
```
Without Pro: drop `--pro`.

## DB migrations
```bash
alembic upgrade head
alembic downgrade -1
alembic revision --autogenerate -m "description"
```

## Build / Publish
```bash
uv build
uv run twine check --strict dist/*
uv publish
```

## Release flow
```bash
python scripts/prepare-release.py # strip -dev suffix, commit
git tag -s ontokit-X.Y.Z
git push --tags # CI/CD publishes
python scripts/set-version.py X.Y.Z # set next dev version (adds -dev)
```

## Migration: old → bare git repos
```bash
python scripts/migrate_to_bare_repos.py --dry-run
python scripts/migrate_to_bare_repos.py
python scripts/migrate_to_bare_repos.py --keep-old
```

## System utilities (Linux/WSL2)
Standard GNU coreutils. `cd`, `ls`, `grep`, `find`, `git` behave normally.
Prefer Serena's `find_file`, `search_for_pattern`, `find_symbol` over shell `find`/`grep` when working inside the repo.
49 changes: 49 additions & 0 deletions .serena/memories/task_completion_checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# When a Coding Task Is Complete — ontokit-api

Run these BEFORE declaring work done or committing:

1. **Lint + auto-fix**
```bash
make lint # or: ruff check ontokit/ tests/ --fix
```

2. **Format**
```bash
make format # or: ruff format ontokit/ tests/
```

3. **Type check (strict mypy)**
```bash
make typecheck # or: mypy ontokit/
```

4. **Tests with coverage**
```bash
make test # or: pytest tests/ -v --cov=ontokit
```

5. **(Optional/CI) Security scan**
```bash
semgrep --pro --config p/default --config p/owasp-top-ten --config p/python --config p/fastapi --config p/jwt
# drop --pro if no Pro entitlement
```

6. **DB schema changes** — generate + commit a migration:
```bash
alembic revision --autogenerate -m "description"
alembic upgrade head # verify it applies cleanly
```

7. **Pre-commit** runs ruff + mypy automatically on commit (installed via `make setup`).
Don't bypass with `--no-verify` unless explicitly authorized.

8. **CI** runs `semgrep ci` (diff-aware) — keep `.semgrepignore` honest.

## Release-specific
For a release, follow `RELEASING.md`:
```bash
python scripts/prepare-release.py
git tag -s ontokit-X.Y.Z
git push --tags
python scripts/set-version.py X.Y.Z
```
Loading
Loading