{"id":50686765,"url":"https://github.com/psielta/anubis","last_synced_at":"2026-06-08T23:32:32.564Z","repository":{"id":362894238,"uuid":"1260969587","full_name":"psielta/anubis","owner":"psielta","description":"Portfolio digital-library app inspired by BookFusion, built with FastAPI, Angular, PostgreSQL and AI-assisted study workflows.","archived":false,"fork":false,"pushed_at":"2026-06-06T12:48:38.000Z","size":115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-06T13:12:53.563Z","etag":null,"topics":["ai-study","alembic","angular","angular-material","bookfusion-inspired","digital-library","docker-compose","fastapi","full-stack","jwt-auth","portfolio","postgresql","python","sqlalchemy","typescript"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/psielta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-06T04:44:12.000Z","updated_at":"2026-06-06T12:48:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/psielta/anubis","commit_stats":null,"previous_names":["psielta/anubis"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/psielta/anubis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psielta%2Fanubis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psielta%2Fanubis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psielta%2Fanubis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psielta%2Fanubis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/psielta","download_url":"https://codeload.github.com/psielta/anubis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psielta%2Fanubis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34085321,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-study","alembic","angular","angular-material","bookfusion-inspired","digital-library","docker-compose","fastapi","full-stack","jwt-auth","portfolio","postgresql","python","sqlalchemy","typescript"],"created_at":"2026-06-08T23:32:31.640Z","updated_at":"2026-06-08T23:32:32.556Z","avatar_url":"https://github.com/psielta.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/anubis-logo.svg\" alt=\"Anubis\" width=\"140\" height=\"140\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eAnubis\u003c/h1\u003e\n\nAnubis is a portfolio full-stack application inspired by BookFusion: a personal\ndigital library where users can organize books, read and study long-form\ncontent, and use AI as a study companion while reading.\n\nThis repository currently contains the scalable application foundation from the\napproved bootstrap plan:\n\n- FastAPI backend with async SQLAlchemy, Alembic and PostgreSQL\n- Angular 21 frontend with Angular Material and standalone/lazy-loaded routes\n- JWT authentication with short-lived access tokens and rotated httpOnly refresh\n  cookies\n- Docker Compose PostgreSQL and MinIO for local development\n- Backend quality gates and auth tests\n\nThe next product iterations should turn this foundation into a user-facing\ndigital reading platform: library management, book import, reader UI,\nannotations, study notes, reading progress and AI-assisted study workflows.\n\n## Product Direction\n\nAnubis is not a BookFusion integration and is not affiliated with BookFusion.\nIt is a portfolio project that uses the same broad product category as\ninspiration: a digital library and reading/study environment.\n\nCore product goals:\n\n- Let users build and manage a private digital book library.\n- Support book metadata, collections, reading status and progress.\n- Provide a clean reading and study interface.\n- Let users create highlights, annotations and study notes.\n- Add AI features that help during study without replacing the reading process.\n\nPlanned AI study capabilities:\n\n- Ask questions about the current book or selected passage.\n- Summarize chapters or selected sections.\n- Generate flashcards and review prompts from highlights.\n- Explain difficult excerpts in simpler language.\n- Build study plans and reading recaps from user activity.\n\n## Current Implementation Status\n\nImplemented:\n\n- User registration and login.\n- Protected app shell with a stacked top-navigation layout (portrait-friendly).\n- Access token stored client-side for API calls.\n- Refresh token stored as an httpOnly cookie scoped to auth routes.\n- Refresh token rotation with stale-token rejection.\n- PostgreSQL connection through SQLAlchemy async sessions.\n- Alembic migrations for the users table and refresh-token hash.\n- Backend tests covering auth, refresh, logout and duplicate registration.\n- Angular route guard, auth interceptor and refresh flow.\n- Book import: PDF upload (up to 250 MB) to MinIO with owner-scoped library API and UI.\n- Book covers: manual image upload plus automatic PDF first-page extraction.\n- In-app PDF reader (continuous scroll, zoom, table of contents from the PDF outline).\n- Reading progress: resumes where you left off, with progress bars in the library.\n- Collections: organise books into collections, with search and pagination in the library.\n- AI study assistant: ask, summarize and generate flashcards over a book or chapter\n  (or a selected passage) via the Gemini API — streamed over SSE with the model's\n  reasoning and rendered as Markdown. Requires `GEMINI_API_KEY` in `backend/.env`.\n\nNot implemented yet:\n\n- Highlights, annotations and notes (persisted).\n- AI embeddings / retrieval-augmented search across the whole library.\n- Production deployment containers for backend/frontend.\n\n## Tech Stack\n\nBackend:\n\n- Python 3.13\n- FastAPI\n- SQLAlchemy 2.x async\n- asyncpg\n- Alembic\n- PostgreSQL\n- PyJWT\n- Passlib/bcrypt\n- pytest, ruff, mypy\n- aioboto3 (MinIO / S3)\n\nFrontend:\n\n- Angular 21\n- Angular Material\n- Standalone components\n- Functional route guards and interceptors\n- Signals for auth state\n\nInfrastructure:\n\n- Docker\n- Docker Compose\n- PostgreSQL 17\n\n## Repository Layout\n\n```text\nanubis/\n|-- docker-compose.yml\n|-- README.md\n|-- AGENT.md\n|-- CLAUDE.md\n|-- backend/\n|   |-- alembic/\n|   |-- app/\n|   |   |-- api/\n|   |   |-- core/\n|   |   |-- crud/\n|   |   |-- db/\n|   |   |-- models/\n|   |   |-- schemas/\n|   |   `-- tests/\n|   |-- alembic.ini\n|   |-- mypy.ini\n|   |-- pytest.ini\n|   `-- requirements.txt\n`-- frontend/\n    `-- anubis-web/\n        `-- src/\n            `-- app/\n                |-- core/\n                |-- features/\n                |-- layout/\n                `-- shared/\n```\n\n## Local Setup\n\n### 1. Database and object storage\n\nFrom the repository root:\n\n```powershell\nCopy-Item .env.example .env\ndocker compose up -d db minio minio-init\ndocker compose ps\n```\n\nThe local Postgres port is configured through `POSTGRES_PORT` in `.env`.\nThis workspace currently uses `5433` to avoid conflicts with local PostgreSQL\ninstallations.\n\nMinIO serves S3-compatible object storage for uploaded books:\n\n- S3 API: `http://localhost:9000` (override with `MINIO_API_PORT`)\n- Console: `http://localhost:9001` (override with `MINIO_CONSOLE_PORT`)\n- Bucket: `anubis-library` (created privately by `minio-init`)\n\nSet `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` in the root `.env`. The backend\nreads matching credentials from `backend/.env` as `S3_ACCESS_KEY` /\n`S3_SECRET_KEY`.\n\n### 2. Backend\n\n```powershell\ncd backend\nCopy-Item .env.example .env\n# Ensure S3_ACCESS_KEY / S3_SECRET_KEY match MINIO_ROOT_USER / MINIO_ROOT_PASSWORD\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install --upgrade pip\npip install -r requirements.txt\nalembic upgrade head\nuvicorn app.main:app --reload --port 8000\n```\n\nBackend URLs:\n\n- API: `http://localhost:8000/api/v1`\n- Docs: `http://localhost:8000/docs`\n- Health: `http://localhost:8000/health`\n\n### 3. Frontend\n\n```powershell\ncd frontend/anubis-web\nnpm install\nnpm start\n```\n\nFrontend URL:\n\n- App: `http://localhost:4200`\n\n## Validation\n\nBackend:\n\n```powershell\ncd backend\n.\\.venv\\Scripts\\Activate.ps1\npytest -q\nruff check .\nmypy app\n```\n\nFrontend:\n\n```powershell\ncd frontend/anubis-web\nnpm run build\n```\n\nEnd-to-end smoke verified with Playwright MCP:\n\n- Logged-out `/dashboard` redirects to `/login?returnUrl=/dashboard`.\n- Registration succeeds.\n- Duplicate registration returns a visible error.\n- Login lands on dashboard.\n- Dashboard displays the current user.\n- Refresh cookie is httpOnly and scoped to `/api/v1/auth`.\n- Reload restores user state.\n- Removing the access token triggers cookie-based refresh.\n- Logout clears local token and invalidates the refresh session.\n\n## Authentication Model\n\n- Access token: short-lived JWT returned in the response body and stored in\n  `localStorage` for API authorization.\n- Refresh token: long-lived JWT stored as an httpOnly cookie, scoped to\n  `/api/v1/auth`.\n- Refresh rotation: each refresh generates a new `jti`, stores its hash on the\n  user row, and rejects stale refresh tokens.\n- Logout clears the refresh-token hash server-side and deletes the cookie.\n\nFuture hardening:\n\n- Move access tokens from `localStorage` to memory.\n- Add CSRF protection for cookie-bearing auth endpoints.\n- Move refresh-token sessions to a dedicated table for multi-device support.\n- Add rate limiting and structured audit logging.\n\n## Product Roadmap\n\nSuggested next milestones:\n\n1. Library shelves/collections and reading status.\n2. Reader shell: table of contents, progress and responsive reading layout.\n3. Automatic metadata extraction on import.\n4. Highlights, notes and bookmarks.\n5. Study tools: highlights, notes and bookmarks.\n6. AI study assistant: passage Q\u0026A, summaries and flashcard generation.\n7. Reading analytics: streaks, progress and study history.\n8. Production packaging: backend/frontend Dockerfiles and reverse proxy.\n\n## Portfolio Notes\n\nThis project should demonstrate:\n\n- Clean full-stack architecture.\n- Practical authentication and session handling.\n- Scalable backend and frontend boundaries.\n- Product thinking around digital reading and AI-assisted study.\n- A path from a working bootstrap to a real SaaS-style application.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsielta%2Fanubis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpsielta%2Fanubis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsielta%2Fanubis/lists"}