Skip to content

Commit 7cd83f2

Browse files
committed
Add portfolio documentation
1 parent 6aaaceb commit 7cd83f2

3 files changed

Lines changed: 524 additions & 0 deletions

File tree

.portfolio/architecture.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# Architecture Overview
2+
3+
## System Architecture Diagram
4+
5+
```mermaid
6+
graph TB
7+
subgraph CLI["CLI Layer (cli.py)"]
8+
NEW[new command]
9+
AUDIT[audit command]
10+
UPGRADE[upgrade command]
11+
ADD[add command]
12+
end
13+
14+
subgraph Models["Data Models (models.py)"]
15+
PC[ProjectConfig]
16+
PT[ProjectType]
17+
PV[PythonVersion]
18+
LIC[License]
19+
TC[ToolingConfig]
20+
FC[FeaturesConfig]
21+
AI[AuthorInfo]
22+
end
23+
24+
subgraph Generator["Generation Engine (generator.py)"]
25+
JINJA[Jinja2 Environment]
26+
TMPL[Template Rendering]
27+
FS[File System Operations]
28+
GIT[Git Initialization]
29+
VAL[Validation]
30+
end
31+
32+
subgraph Templates["Template System"]
33+
CORE[Core Templates]
34+
OPT[Optional Templates]
35+
COND[Conditional Templates]
36+
end
37+
38+
subgraph Auditor["Audit Engine (auditor.py)"]
39+
DET[Tool Detection]
40+
REC[Recommendation Engine]
41+
SCORE[Scoring System]
42+
end
43+
44+
subgraph Upgrader["Migration Engine (upgrader.py)"]
45+
PLAN[Migration Planner]
46+
PKG[Package Manager Migration]
47+
LINT[Linter Migration]
48+
TYPE[Type Checker Migration]
49+
end
50+
51+
NEW --> PC
52+
NEW --> Generator
53+
AUDIT --> Auditor
54+
UPGRADE --> Upgrader
55+
ADD --> Generator
56+
57+
PC --> PT
58+
PC --> PV
59+
PC --> LIC
60+
PC --> TC
61+
PC --> FC
62+
PC --> AI
63+
64+
PC --> JINJA
65+
JINJA --> TMPL
66+
TMPL --> Templates
67+
TMPL --> FS
68+
FS --> GIT
69+
GIT --> VAL
70+
71+
CORE --> TMPL
72+
OPT --> TMPL
73+
COND --> TMPL
74+
75+
DET --> REC
76+
REC --> SCORE
77+
78+
Auditor --> PLAN
79+
PLAN --> PKG
80+
PLAN --> LINT
81+
PLAN --> TYPE
82+
83+
style CLI fill:#e1f5fe
84+
style Models fill:#f3e5f5
85+
style Generator fill:#e8f5e9
86+
style Templates fill:#fff3e0
87+
style Auditor fill:#fce4ec
88+
style Upgrader fill:#e0f2f1
89+
```
90+
91+
## Data Flow Diagram
92+
93+
```mermaid
94+
flowchart LR
95+
subgraph Input
96+
USER[User Input]
97+
PROMPTS[Interactive Prompts]
98+
FLAGS[CLI Flags]
99+
end
100+
101+
subgraph Processing
102+
CONFIG[ProjectConfig Validation]
103+
RENDER[Template Rendering]
104+
WRITE[File Writing]
105+
end
106+
107+
subgraph Output
108+
PROJECT[Generated Project]
109+
STRUCTURE[Directory Structure]
110+
FILES[Configuration Files]
111+
end
112+
113+
USER --> PROMPTS
114+
USER --> FLAGS
115+
PROMPTS --> CONFIG
116+
FLAGS --> CONFIG
117+
CONFIG --> RENDER
118+
RENDER --> WRITE
119+
WRITE --> STRUCTURE
120+
WRITE --> FILES
121+
STRUCTURE --> PROJECT
122+
FILES --> PROJECT
123+
```
124+
125+
## Key Architectural Decisions
126+
127+
### 1. Typer for CLI Framework
128+
129+
I chose Typer over alternatives like Click or argparse for several reasons:
130+
131+
- **Type hint integration**: Typer infers CLI options directly from Python type annotations, reducing boilerplate
132+
- **Rich integration**: Built-in support for beautiful terminal output via Rich library
133+
- **Automatic help generation**: Help text is generated from docstrings and type hints
134+
- **Modern Python patterns**: Leverages Python 3.9+ features naturally
135+
136+
### 2. Pydantic for Data Validation
137+
138+
I use Pydantic models throughout the application for configuration management:
139+
140+
- **Runtime validation**: User input is validated immediately with clear error messages
141+
- **Computed properties**: Complex logic like `package_name` derivation is encapsulated in the model
142+
- **Serialization**: Easy conversion between TOML, JSON, and Python objects
143+
- **Type safety**: Full IDE support and static type checking compatibility
144+
145+
### 3. Jinja2 Template System
146+
147+
I selected Jinja2 for template rendering because:
148+
149+
- **Mature ecosystem**: Well-documented with extensive community support
150+
- **Conditional rendering**: Templates can include logic for project-type-specific content
151+
- **Maintainability**: Separating templates from code makes them easier to update
152+
- **Familiarity**: Most Python developers already know Jinja2 syntax
153+
154+
### 4. Pipeline Architecture for Generation
155+
156+
The generator follows a sequential pipeline pattern:
157+
158+
```
159+
Validate -> Create Dirs -> Render Templates -> Write Files -> Init Git -> Validate Output
160+
```
161+
162+
This design provides:
163+
164+
- **Atomicity**: If any step fails, cleanup removes partial work
165+
- **Debuggability**: Each step can be tested independently
166+
- **Extensibility**: New steps can be inserted without modifying existing ones
167+
168+
### 5. Detection-Based Auditing
169+
170+
The auditor uses file-based detection rather than requiring explicit configuration:
171+
172+
- **Zero configuration**: Works on any Python project without setup
173+
- **Multiple signals**: Checks lock files, config files, and tool sections in pyproject.toml
174+
- **Graceful degradation**: Unknown projects get generic recommendations
175+
176+
### 6. Comment-Preserving TOML Manipulation
177+
178+
I use `tomlkit` instead of `tomli` for writing TOML files during upgrades:
179+
180+
- **Preserves comments**: User's existing documentation in pyproject.toml is maintained
181+
- **Maintains formatting**: Whitespace and structure remain intact
182+
- **Safer migrations**: Less risk of destroying important configuration
183+
184+
### 7. Modular Feature System
185+
186+
Features like Docker, GitHub Actions, and VS Code settings are modular add-ons:
187+
188+
- **Optional by default**: Core functionality doesn't depend on optional features
189+
- **Post-creation addition**: Features can be added to existing projects via `quickforge add`
190+
- **Independent templates**: Each feature has its own template set
191+
192+
## Module Responsibilities
193+
194+
| Module | Responsibility |
195+
|--------|---------------|
196+
| `cli.py` | Command definitions, argument parsing, interactive prompts, output formatting |
197+
| `models.py` | Data validation, configuration structure, computed properties, serialization |
198+
| `generator.py` | Directory creation, template rendering, file writing, git initialization |
199+
| `auditor.py` | Tool detection, configuration analysis, recommendation generation, scoring |
200+
| `upgrader.py` | Migration planning, TOML manipulation, tool-specific migration logic |
201+
| `templates/` | Jinja2 templates for all generated files |
202+
203+
## Error Handling Strategy
204+
205+
I implemented defensive error handling throughout:
206+
207+
1. **CLI level**: Catch exceptions and display user-friendly messages
208+
2. **Generator level**: Clean up partial work on failure
209+
3. **Validation level**: Provide specific error messages for invalid input
210+
4. **Upgrade level**: Create backups before making changes

.portfolio/qa.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Project Q&A
2+
3+
## Project Overview
4+
5+
**quickforge** is a modern Python project bootstrapper that creates production-ready Python projects with a single command. It solves the problem of repetitive project setup by generating complete project structures with 2025's best toolchain already configured: uv for package management, ruff for linting/formatting, basedpyright for type checking, and pytest for testing. The target users are Python developers who want to start new projects quickly without spending hours configuring build tools, CI/CD pipelines, and development environments.
6+
7+
## Key Features
8+
9+
### 1. One-Command Project Creation
10+
11+
Run `quickforge new myproject` and get a complete, working project with:
12+
- Proper package structure (src layout)
13+
- All tools configured in pyproject.toml
14+
- GitHub Actions CI/CD pipeline
15+
- Pre-commit hooks ready to install
16+
- VS Code settings optimized for the toolchain
17+
- Test skeleton with pytest and coverage
18+
19+
### 2. Multiple Project Types
20+
21+
I support five project types tailored to different use cases:
22+
- **library**: PyPI-publishable packages with src layout
23+
- **cli**: Command-line tools with Typer integration
24+
- **api**: FastAPI/Flask web services
25+
- **app**: Standalone applications
26+
- **script**: Single-file scripts with PEP 723 inline dependencies
27+
28+
### 3. Interactive and Scriptable
29+
30+
The CLI works in two modes:
31+
- **Interactive**: Prompts guide you through all options with descriptions
32+
- **Non-interactive**: Pass flags for CI/CD usage (`--yes` skips all prompts)
33+
34+
### 4. Project Auditing
35+
36+
The `quickforge audit` command analyzes existing projects and identifies:
37+
- Legacy tooling (black, flake8, mypy) that could be modernized
38+
- Missing type annotations and coverage
39+
- Configuration improvements
40+
- Security best practices
41+
42+
### 5. Automated Migration
43+
44+
The `quickforge upgrade` command migrates projects from:
45+
- Poetry/pip/pipenv/setuptools to uv
46+
- black/isort/flake8 to ruff
47+
- mypy to basedpyright
48+
49+
It preserves comments and formatting in existing configuration files.
50+
51+
### 6. Feature Addition
52+
53+
Add optional features to existing projects with `quickforge add`:
54+
- github-actions: CI/CD workflow
55+
- docker: Dockerfile and docker-compose.yml
56+
- docs: MkDocs with Material theme
57+
- pre-commit: Git hooks configuration
58+
- vscode: IDE settings and extensions
59+
- devcontainer: Dev container for VS Code
60+
61+
## Technical Highlights
62+
63+
### Challenge: Comment-Preserving TOML Updates
64+
65+
When upgrading projects, I needed to modify pyproject.toml without destroying users' carefully written comments and documentation. I solved this by using `tomlkit` instead of standard TOML libraries. tomlkit parses TOML into a document model that preserves whitespace, comments, and formatting, allowing surgical modifications.
66+
67+
### Challenge: Cross-Platform Path Handling
68+
69+
Template paths needed to work across macOS, Linux, and Windows. I used `pathlib.Path` throughout and carefully handled path separators in templates. The src layout path is dynamically computed based on project type.
70+
71+
### Challenge: Atomic Project Generation
72+
73+
If generation fails midway, users shouldn't be left with a broken partial project. I implemented cleanup logic that removes partially created directories on failure, and validation that verifies the generated project is syntactically correct before reporting success.
74+
75+
### Innovation: Detection-Based Auditing
76+
77+
Rather than requiring users to declare their tooling, the auditor automatically detects what tools are in use by checking for lock files, configuration sections, and tool-specific files. This zero-configuration approach means it works on any Python project.
78+
79+
### Innovation: Template Condition System
80+
81+
Templates are conditionally rendered based on project configuration. For example, `cli.py.j2` is only rendered for CLI projects, while `main.py.j2` is rendered for app and API projects. This keeps the generated code minimal and relevant.
82+
83+
## Frequently Asked Questions
84+
85+
### Q1: Why create another project scaffolding tool?
86+
87+
I found that existing tools either generate outdated structures (using setup.py, black, mypy) or require significant configuration. I wanted a tool that embodies 2025 best practices out of the box, with zero configuration needed for the common case. quickforge generates exactly what I would set up manually for a new project.
88+
89+
### Q2: Why uv instead of Poetry or pip?
90+
91+
uv is 10-100x faster than pip and Poetry because it's written in Rust. It handles dependency resolution, virtual environments, and Python version management in one tool. The speed difference is noticeable on every operation, making development more pleasant.
92+
93+
### Q3: Why ruff instead of black and flake8?
94+
95+
ruff combines linting (flake8, pylint) and formatting (black, isort) into one tool that's 10-100x faster. Having one configuration section instead of three separate tools simplifies maintenance. ruff also has more rules and better autofix capabilities.
96+
97+
### Q4: Why basedpyright instead of mypy?
98+
99+
basedpyright is faster (3-5x), has better error messages, and integrates seamlessly with VS Code. It's stricter by default, which catches more bugs. The "based" fork adds additional checks beyond standard pyright.
100+
101+
### Q5: Can I customize the generated templates?
102+
103+
Currently, templates are bundled with the package and not user-customizable. This is intentional to ensure consistency and correctness. If you need significant customization, you can use quickforge as a starting point and modify the generated files, or fork the project.
104+
105+
### Q6: Does quickforge support monorepos?
106+
107+
Not currently. Each invocation creates a single project. For monorepos, I'd recommend using uv workspaces directly. This might be added in a future version.
108+
109+
### Q7: How does the audit scoring work?
110+
111+
The audit starts at 100 points and deducts based on findings:
112+
- Critical issues: -20 points
113+
- Errors: -10 points
114+
- Warnings: -5 points
115+
- Info: -1 point
116+
117+
A score above 80 is considered healthy, 60-80 needs attention, and below 60 indicates significant technical debt.
118+
119+
### Q8: What happens if the upgrade fails?
120+
121+
Before making any changes, `quickforge upgrade` creates a timestamped backup of all configuration files in `.quickforge_backup_TIMESTAMP/`. If something goes wrong, you can restore from this backup. The upgrade also supports `--dry-run` to preview changes without applying them.
122+
123+
### Q9: Why is the coverage requirement set at 80%?
124+
125+
I believe 80% is a pragmatic target that encourages good testing habits without becoming burdensome. It allows for untested edge cases and configuration code while ensuring core functionality is covered. The threshold is configurable in the generated pyproject.toml.
126+
127+
### Q10: How do I contribute to quickforge?
128+
129+
The project is open source on GitHub. To contribute:
130+
1. Clone the repository
131+
2. Run `uv sync --extra dev` to install dependencies
132+
3. Run `uv run pre-commit install` to set up hooks
133+
4. Make changes and ensure `uv run pytest` passes
134+
5. Submit a pull request
135+
136+
I welcome contributions for new project types, additional features, and bug fixes.

0 commit comments

Comments
 (0)