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
16 changes: 11 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,26 @@ faststack/

## Common Commands

Run `make` or `make help` for all targets. Key ones:

```bash
make install # poetry install
make test # pytest
make test-verbose # pytest -v
make install-dev # venv + all deps + pre-commit hooks
make check # lint + typecheck + test with 85% coverage (CI gate)
make test # pytest with coverage
make test-unit # core + template tests only
make test-integration # CLI command tests
make lint # ruff check + black --check
make format # ruff fix + black
make typecheck # mypy faststack_core/ cli/
make check # lint + typecheck + test (CI gate)
make pre-commit # run all pre-commit hooks
make clean # remove caches, build artifacts
make help # list all targets
```

## Key Documents

- `DEVELOPING.md` — development setup, project structure, how generation works
- `TESTING.md` — test organization, markers, coverage, patterns
- `CONTRIBUTING.md` — workflow, code standards, PR process
- `docs/design/fastapi-generator-plan.md` — design blueprint
- `docs/implementation/v1-implementation-plan.md` — build sequence
- `docs/architecture/adr/` — Architecture Decision Records (the reasoning)
99 changes: 99 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Contributing to FastStack

## Getting Started

```bash
git clone https://github.com/manavgup/faststack.git
cd faststack
make install-dev # venv + deps + pre-commit hooks
make check # verify everything works
```

See [DEVELOPING.md](DEVELOPING.md) for project structure and how code generation works.
See [TESTING.md](TESTING.md) for test organization, markers, and patterns.

## Development Workflow

1. **Create an issue** before starting work on features or non-trivial fixes
2. **Create a branch** from `main`:
```bash
git checkout -b feature/short-description
```
3. **Make your changes** — write code, add tests
4. **Run the full check suite:**
```bash
make check # lint + typecheck + tests with 85% coverage
```
5. **Commit** with a clear message:
```bash
git commit -m "Add foo to bar for baz"
```
6. **Push and create a PR** against `main`

## Code Standards

### Python

- **Python 3.12+** with type hints
- **Line length:** 120 characters (ruff + black)
- **Formatting:** `make format` (ruff --fix + black)
- **Linting:** `make lint` (ruff + black --check)
- **Type checking:** `make typecheck` (mypy)

### Naming

- `snake_case` for functions, variables, file names
- `PascalCase` for classes
- `UPPER_CASE` for constants

### Tests

- Every feature or bug fix needs tests
- Unit tests for logic, integration tests for CLI commands
- Use fake repositories (Protocol-based), not mocks
- See [TESTING.md](TESTING.md) for patterns

### Templates

When modifying Jinja2 templates in `templates/simple/`:

- Verify rendered output is valid Python: `ast.parse(output)`
- Test with multiple entity types (simple, with FKs, with enums, self-referential)
- Remember the REGENERATABLE vs PRESERVED distinction

## CI Checks

All PRs must pass these required checks before merging:

| Check | Workflow | What it runs |
|-------|----------|--------------|
| Ruff & Black | `lint.yml` | `ruff check .` + `black --check .` |
| Mypy | `lint.yml` | `mypy faststack_core/ cli/` |
| Test (py3.12) | `ci.yml` | `pytest` with 85% coverage threshold |
| Pre-commit | `pre-commit.yml` | All pre-commit hooks |
| Package Build | `ci.yml` | `poetry build` + `twine check` |

Run `make check` locally before pushing — it mirrors the CI gate.

## Commit Messages

Write clear, imperative commit messages:

```
Add entity list command with staleness detection
Fix pluralization for already-plural entity names
Update router template to wire Depends() injection
```

Lead with what the commit does, not what you did. One sentence is usually enough. Add a body only if the "why" isn't obvious.

## Pull Requests

- Keep PRs focused — one feature or fix per PR
- Title: short (under 70 chars), imperative
- Description: what changed and why, not a line-by-line diff
- Link the issue: `Closes #123`

## Architecture Decisions

Non-trivial design decisions are tracked in `docs/architecture/adr/`. If your change introduces a new pattern or overrides an existing decision, add or update an ADR.
127 changes: 127 additions & 0 deletions DEVELOPING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Developing FastStack

This guide gets you from zero to a working development environment.

## Prerequisites

- **Python 3.12+**
- **Poetry** — `pipx install poetry`
- **Git**

## Quick Start

```bash
git clone https://github.com/manavgup/faststack.git
cd faststack
make install-dev
make check
```

`make install-dev` creates a virtual environment, installs all dependencies, and sets up pre-commit hooks. `make check` runs lint + typecheck + tests with coverage — the same gate that CI runs.

## Project Structure

```
faststack/
├── faststack_core/ # Runtime library (users import this)
│ ├── base/ # Entity bases, Repository Protocol, CrudService
│ ├── exceptions/ # DomainError hierarchy + RFC 7807 handlers
│ ├── database/ # Async session config, get_db dependency
│ ├── logging/ # Structured JSON logger, sensitive data masking
│ ├── middleware/ # Correlation ID, request logging, security headers
│ ├── health/ # Health check endpoints
│ ├── settings/ # FastStackConfig dataclass
│ └── setup.py # One-call setup_app() for all middleware
├── cli/ # CLI tool (faststack command, built with Click)
│ ├── cmd_init.py # faststack init
│ ├── cmd_add_entity.py # faststack add-entity
│ ├── cmd_generate.py # faststack generate
│ ├── cmd_list.py # faststack list
│ ├── cmd_migrate.py # faststack migrate
│ ├── yaml_parser.py # YAML entity definitions → EntityDefinition
│ ├── model_introspector.py # AST-based SQLAlchemy model reader
│ └── field_mappings.py # YAML ↔ SQLAlchemy ↔ Pydantic type mappings
├── templates/ # Jinja2 templates for code generation
│ ├── project/ # Project scaffold (8 templates)
│ └── simple/ # Entity templates (11 templates)
├── tests/ # Framework tests
│ ├── test_core/ # Runtime library tests (unit)
│ ├── test_cli/ # CLI command tests (integration)
│ ├── test_templates/ # Template rendering tests (unit)
│ └── test_e2e/ # End-to-end scaffold validation
├── examples/ # Example YAML files + smoke tests
└── docs/ # Design docs, ADRs, implementation plan
```

## Make Targets

Run `make` or `make help` to see all available targets, organized by category:

- **🌱 Installation** — `venv`, `install`, `install-dev`, `update`
- **🧪 Testing** — `test`, `test-unit`, `test-integration`, `test-e2e`, `coverage`
- **🔍 Quality** — `lint`, `format`, `typecheck`, `check`, `pre-commit`
- **🧹 Cleanup** — `clean`, `clean-all`

## How Code Generation Works

FastStack generates projects from YAML entity definitions. The pipeline:

```
entities.yaml → yaml_parser.py → EntityDefinition → Jinja2 templates → .py files
```

1. **YAML parsing** (`cli/yaml_parser.py`) — reads entity fields, resolves FK relationships
2. **Template rendering** (`templates/simple/*.j2`) — generates 9 files per entity:
- `model.py` — SQLAlchemy ORM model
- `schema.py` — Pydantic Create/Update/Response schemas
- `repository.py` — SqlAlchemyRepository subclass
- `service.py` — CrudService subclass with lifecycle hooks
- `router.py` — FastAPI router with CRUD endpoints + Depends() wiring
- `factory.py` — Polyfactory test data factory
- `fake_repository.py` — In-memory repository for unit tests
- `test_unit_service.py` — Service unit tests
- `test_integration.py` — API integration tests
3. **Registry files** (multi-entity) — generated after all entities:
- `dependencies.py` — DI providers for all entities
- `tests/integration/conftest.py` — AsyncClient fixture with fake repo overrides

### File Ownership

Templates are classified as **REGENERATABLE** or **PRESERVED**:

| REGENERATABLE (safe to overwrite) | PRESERVED (user owns) |
|---|---|
| schemas, fakes, factories | models, repos, services, routers, tests |
| `dependencies.py`, integration conftest | — |

`faststack generate` only overwrites REGENERATABLE files. Use `--force` for PRESERVED files.

### Model Introspection

`faststack generate` reads existing SQLAlchemy models via AST parsing (`cli/model_introspector.py`), extracts an `EntityDefinition`, and regenerates derived files. The model is the source of truth — not YAML.

## CLI Commands

```bash
faststack init <project> [--entities entities.yaml] # Scaffold project
faststack add-entity <Name> --fields "name:string:required" # Add entity
faststack add-entity <Name> --from-yaml entities.yaml # Add from YAML
faststack generate <Name> # Regenerate derived files
faststack generate --all # Regenerate all entities
faststack list # Show entity status
faststack migrate generate "message" # Create Alembic migration
faststack migrate upgrade # Apply migrations
faststack migrate downgrade # Rollback one migration
```

## Key Design Decisions

See `docs/architecture/adr/` for full rationale. Summary:

- **Async-first** — no sync support (ADR-001)
- **Protocol-based repos** — structural typing, in-memory fakes for tests (ADR-002)
- **YAML input, model source of truth** — AST introspection for regeneration (ADR-003)
- **RFC 7807 errors** — standardized error responses (ADR-004)
- **Lifecycle hooks** — `before_create`, `after_create`, etc. (ADR-005)
- **File ownership** — REGENERATABLE vs PRESERVED (ADR-006)
- **v1 = simple mode only** — DDD deferred to v2 (ADR-007)
Loading
Loading