Skip to content

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

FastAPI Learning Project (Backend + CLI)

This repository is a learning project for building a modern API-first system with:

  • A FastAPI backend for auth, projects, secrets, and AI-assisted querying
  • A Typer-based CLI (envctl) that consumes the backend API
  • PostgreSQL + SQLAlchemy (async) for persistence
  • Redis for OTP flows and transient auth state
  • Gemini models for leak detection and semantic secret lookup

Note: The goal is educational to practice real architecture patterns and integrations in a small but complete system.

What This Project Does

At a high level, this system lets users:

  1. Register and activate accounts using OTP emailed to them
  2. Log in with JWT access/refresh tokens
  3. Create and manage projects with role-based access control
  4. Store secrets per project (encrypted at rest)
  5. Query secrets using an AI-assisted "ask" flow (semantic search + tool calling)
  6. Access all of this from both REST endpoints and a local CLI

Repository Structure

This codebase has two top-level apps:

fastapi-learning/
	backend/   # FastAPI service
	cli/       # Typer command line client (envctl)

Backend key folders

  • app/api/v1: HTTP routers (auth, project, secret, ai)
  • app/services: business logic (auth, project, secrets, embeddings, gemini, otp)
  • app/dependencies: FastAPI dependency layers (auth guards, role checks)
  • app/models: SQLAlchemy ORM models
  • app/schemas: request/response contracts (Pydantic)
  • app/domain: service-level dataclasses (input/output shapes)
  • app/core: config, security, exception system, app lifespan
  • app/db: async session, Redis pool, shared DB primitives
  • alembic/: migrations and migration environment

CLI key folders

  • commands: user-facing commands (login, project, secret, audit)
  • core/client.py: HTTP adapter to backend endpoints
  • core/auth_store.py: local token persistence and JWT expiry checks
  • core/config_store.py: local app dirs, cache, and base URL config
  • core/ui.py: Rich-based terminal error panels

Backend Architecture (Layered)

The backend follows a clean layered style:

  1. Router layer (api/v1)
  • Validates request payloads using schemas
  • Wires dependencies and calls services
  • Maps service output to response models
  1. Dependency layer (dependencies)
  • Resolves current user from bearer token
  • Enforces project membership/role authorization
  • Builds a typed ProjectContext passed into services
  1. Service layer (services)
  • Implements core use cases:
    • AuthService: register, activate, login, refresh
    • ProjectService: CRUD + membership management
    • SecretsService: encrypt/decrypt secret values + access checks
    • EmbeddingService: generate/store embeddings + similarity ranking
    • GeminiService: leak scan + streamed query with function calling
    • AuditLogService: structured security/audit events
  1. Data layer (models, db)
  • SQLAlchemy async ORM entities with relationships
  • Async session lifecycle and commit/rollback handling
  • Redis connection pool for OTP and cooldown logic
  1. Cross-cutting (core)
  • config.py: env-driven settings
  • security.py: JWT creation/verification
  • exceptions.py + err_handlers.py: normalized API errors
  • lifespan.py: startup/shutdown hooks (Redis pool)

Major Features and Flows

1) Auth with OTP activation

  • Registration stores inactive user + sends OTP email
  • OTP is stored in Redis as a SHA-256 hash with TTL
  • Activation verifies OTP, activates the account, issues tokens
  • Login returns access + refresh tokens
  • Refresh endpoint rotates access token via refresh token validation

2) Project and role-based access

  • Projects have members with roles: admin, dev, readonly
  • Access checks happen via require_project_role(...)
  • Routes receive a validated ProjectContext (user + project + role)

3) Secret management with encryption

  • On project creation, a per-project DEK is generated and wrapped
  • Secret values are encrypted with the project DEK before DB write
  • Decryption happens only at read-time in service logic
  • Some role/environment combinations are intentionally restricted

4) Audit logging

  • Security-relevant actions (view/create/update/delete secret) are logged
  • Logs include type, status, user, project, and details

5) AI-assisted secret operations

  • Optional pre-create leak scan using Gemini structured output
  • Embedding-based key retrieval (gemini-embedding-001)
  • SSE streaming endpoint for ask flow
  • Gemini tool-calling chooses either:
    • get_secret
    • no_secret_match

CLI Architecture and Behavior

The CLI is designed as a thin API client with local UX state.

  • Typer provides command parsing and help
  • Rich provides tables/panels for friendly terminal output
  • httpx handles all HTTP requests
  • Tokens are stored in ~/.envctl/tokens.json (or ENVCTL_HOME)
  • Access token expiry is checked locally by decoding JWT payload
  • If access token is expired, CLI attempts refresh before request
  • Project name to ID lookup is cached under ~/.envctl/cache/projects.json

API Surface (Current)

Auth:

  • POST /api/v1/auth/register
  • POST /api/v1/auth/activate-user
  • POST /api/v1/auth/login
  • POST /api/v1/auth/resend-otp
  • POST /api/v1/auth/refresh-token

Projects:

  • GET /api/v1/projects/
  • GET /api/v1/projects/{project_id}
  • GET /api/v1/projects/name/?name=...
  • POST /api/v1/projects/
  • PUT /api/v1/projects/{project_id}
  • DELETE /api/v1/projects/{project_id}
  • GET /api/v1/projects/{project_id}/users
  • POST /api/v1/projects/{project_id}/users
  • DELETE /api/v1/projects/{project_id}/users

Secrets:

  • GET /api/v1/projects/{project_id}/secrets/
  • GET /api/v1/projects/{project_id}/secrets/{secret_id}
  • GET /api/v1/projects/{project_id}/secrets/by-name/{secret_name}
  • POST /api/v1/projects/{project_id}/secrets/
  • PUT /api/v1/projects/{project_id}/secrets/{secret_id}
  • DELETE /api/v1/projects/{project_id}/secrets/{secret_id}

AI:

  • POST /api/v1/projects/{project_id}/secrets/query (SSE stream)

Concepts Used in This Learning Project

This project demonstrates practical usage of:

  • FastAPI router composition and dependency injection
  • Pydantic request/response contracts
  • Async SQLAlchemy ORM patterns (select, update, async sessions)
  • PostgreSQL schema evolution with Alembic migrations
  • Redis-backed OTP, cooldown, and attempt tracking
  • JWT auth (access + refresh token strategy)
  • Role-based authorization at dependency level
  • Service-oriented layering and domain DTOs
  • Field-level encryption with Fernet
  • Structured exception modeling and centralized error translation
  • Server-Sent Events (SSE) streaming responses
  • LLM function-calling and embedding similarity retrieval
  • CLI UX patterns with Typer + Rich
  • Local credential/cache persistence with atomic file writes
  • Multi-stage Docker builds for lean runtime images

Local Development

Prerequisites

  • Python 3.11+
  • PostgreSQL
  • Redis
  • uv package manager
  • (Optional but needed for AI features) Google API key

Backend setup

cd backend
uv sync
uv run alembic upgrade head
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

CLI setup

cd cli
uv sync
uv run envctl --help

Run the command from the cli directory. If you are in the repository root, use:

uv run --project cli envctl --help

If you still see Failed to spawn: envctl, reinstall the local CLI package into the uv environment:

cd cli
uv sync --reinstall-package cli
uv run envctl --help

Typical CLI flow

envctl register
envctl user-activate
envctl login
envctl project create
envctl secret create my-project API_KEY "xxx" --env dev
envctl secret ask "what is the API key for staging?" --project my-project

Quality and Tooling

Backend uses:

  • ruff for linting
  • mypy for static type checking

Run checks:

cd backend
uv run ruff check .
uv run mypy

Auto-fix where possible:

uv run ruff check . --fix

Notes and Learning Gaps

  • The CLI audit command is currently a placeholder.
  • Some production hardening is still pending (secrets handling UX, broader tests, stricter env separation).
  • This is intentionally a learning-oriented codebase, not a finished production platform.

About

No description, website, or topics provided.

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages