Full-Stack Entity Generator
Generate a complete FastAPI + SQLAlchemy + Jinja2 application from JSON entity definitions.
This project uses JSON files as a single source of truth and generates:
- Domain entities (dataclasses)
- Application DTOs (Pydantic)
- Repository ports and SQLAlchemy repository implementations
- SQLAlchemy models
- API routers (CRUD) with Bearer JWT authentication
- Frontend routers and HTML templates with custom CSS
- JWT authentication system (login, register, user management)
- i18n scaffolding
- App bootstrap files
Why this project exists
When building CRUD-heavy business apps, the same concepts are repeated in many layers:
- Domain models
- API schemas
- Persistence models
- Web forms and lists
- Authentication and authorization
- Basic translations
This generator removes repetitive boilerplate by deriving those layers from JSON entity specs.
Tech stack
- Python 3.14+ for the generator itself
- Jinja2 templates for code generation
- Generated project stack:
- FastAPI
- SQLAlchemy
- Pydantic
- Jinja2 templates
- PyJWT + bcrypt (authentication)
- Custom CSS (no Bootstrap dependency)
- SQLite (by default)
Repository layout
fsgenerator/
cli.py # CLI entrypoint with argparse
parser.py # Parses app config and entity JSON files
resolver.py # Sorts entities by relation dependencies
type_mapping.py # Maps JSON field types to Python/SQLAlchemy/Pydantic
writer.py # Writes generated files and __init__.py markers
generators/ # Per-layer file generators
templates/ # Jinja2 templates used by generators
sample_entities/ # Starter JSON files for -x/--init scaffolding
json_entities/ # Input JSON entity files (example)
generate.py # Convenience wrapper for fsgenerator CLI
How generation works
- Load app config from app_config.json.
- Load all entity JSON files in the target directory.
- Validate relation targets.
- Topologically sort entities (based on many_to_one and one_to_one dependencies).
- Render templates for each entity and shared files.
- Write output into a generated project folder named by app_name.
Quick start
1. Install dependencies
uv sync
2. Scaffold a starter project (optional)
uv run generate.py -x
This creates a json_entities/ directory in the current folder with sample JSON files and a README explaining the entity format.
3. Generate using the default input folder
uv run generate.py
4. Generate from a custom folder path
uv run generate.py -i ./json_entities
5. Generate into a custom destination parent directory
uv run generate.py -i ./json_entities -o ./output
This creates ./output/<app_name>.
You can pass any directory that contains:
- app_config.json
- one or more entity JSON files
CLI
usage: fsgenerator [-h] [-x] [-i INPUT_DIR] [-o OUTPUT_DIR]
options:
-h, --help show this help message and exit
-x, --init Create a json_entities/ directory with sample starter
files, then exit
-i INPUT_DIR, --input-dir INPUT_DIR
Path to the JSON entities directory (default: ./json_entities)
-o OUTPUT_DIR, --output-dir OUTPUT_DIR
Parent directory for generated output (default: current directory)
If --input-dir is omitted, it defaults to ./json_entities. If --output-dir is omitted, it defaults to the current directory.
Input format
app_config.json
{
"app_name": "my_app",
"id_type": "integer"
}
Fields:
- app_name: Output directory name for the generated app
- id_type: Global ID type for primary and foreign keys
- integer
- uuid
Entity JSON example
{
"name": "company",
"representation": ["name"],
"fields": {
"name": {"type": "string", "maxLength": 80},
"afm": {"type": "string_numeric", "length": 9}
},
"relations": {
"parent": {"type": "many_to_one", "entity": "company"}
},
"unique": {
"unique_name": ["name"],
"unique_parent_name": ["parent", "name"]
}
}
Entity schema details
Root keys
- name: Entity name (used for filenames, routes, table name)
- representation: Fields used for display labels in dropdowns and list views
- fields: Dictionary of scalar fields
- relations: Dictionary of relations
- unique: Named unique constraints
Field options
| Option | Type | Default | Description |
|---|---|---|---|
| type | string | — | Required. One of the supported types below |
| maxLength | integer | — | Maximum string length |
| minLength | integer | — | Minimum string length validation |
| length | integer | — | Exact string length (sets both min and max) |
| isnull | boolean | false | Whether null is allowed (makes the field optional) |
| options | array | — | Required for select type. List of [value, "label"] pairs |
Relation options
- type: many_to_one (currently fully supported in generation)
- entity: Target entity name (must match a JSON filename)
Supported scalar field types
| Type | Python type | SQLAlchemy type | Notes |
|---|---|---|---|
| integer | int | Integer | |
| string | str | String(N) | Use maxLength to set length |
| string_numeric | str | String(N) | Adds ^\d+$ regex validation |
| iso-date | datetime.date | Date | |
| iso-datetime | datetime.datetime | DateTime | |
| time | datetime.time | Time | |
| value | Decimal | Numeric(10,2) | For monetary values |
| float | float | Float | |
| percent | Decimal | Numeric(5,2) | For percentage values |
| key | int | Integer | Generic integer key |
| select | int | Integer | Requires options field |
Mapping behavior is defined in fsgenerator/type_mapping.py.
Relationship behavior
- Relation definitions are parsed for all listed relation types.
- Code generation currently emits foreign key columns and object relationships for:
- many_to_one
- one_to_one
- Dependency sorting is based on many_to_one and one_to_one relations.
- Relation fields are placed before data fields in all generated files (entities, DTOs, models, templates).
Unique constraints
Named unique constraints are generated at SQLAlchemy table level.
When a unique constraint references a relation field name, the generator maps it to the corresponding foreign key column name (for example, parent -> parent_id).
Authentication
The generated application includes a complete JWT-based authentication system:
- Login/Register pages with bcrypt password hashing
- JWT tokens stored in HTTP-only cookies (60-minute expiry)
- Auth middleware that redirects unauthenticated users to the login page
- API Bearer auth — all REST API endpoints require a valid JWT in the Authorization header
- Admin user seeded on first startup (email:
admin@admin.com, password:admin) - User management — admin users can toggle active/admin status of other users
- Change password — authenticated users can change their own password
Public paths (login, register, static files, API docs) are accessible without authentication.
Generated output structure
For each entity named example, the generator produces:
- domain/entities/example.py
- application/dtos/example.py
- domain/ports/example.py
- application/use_cases/example.py
- infrastructure/persistence/sqlalchemy/models/example.py
- infrastructure/persistence/sqlalchemy/repositories/example.py
- infrastructure/web/fastapi/routers/example.py (API)
- infrastructure/web/fastapi/routers/example_frontend.py
- templates/example_list.html
- templates/example_form.html
Shared files:
- main.py (FastAPI app with auth middleware and admin seeding)
- pyproject.toml
- static/style.css (custom CSS design system)
- infrastructure/web/fastapi/dependencies.py
- infrastructure/web/fastapi/routers/i18n.py
- infrastructure/persistence/sqlalchemy/models/__init__.py
- infrastructure/persistence/sqlalchemy/models/auth_models.py
- auth_security.py (JWT + bcrypt utilities)
- infrastructure/web/fastapi/routers/auth.py
- templates/base.html
- templates/home.html
- templates/login.html
- templates/register.html
- templates/change_password.html
- templates/admin_users.html
- i18n_helper.py
- i18n/en.json
The generator also creates missing __init__.py files in generated package directories.
i18n
The generator creates i18n/en.json with:
- Common UI and error labels
- Per-entity labels
- Per-field labels
- Labels for many_to_one and one_to_one relation selectors
- Authentication labels (login, register, password, user management)
The generated app includes:
- Translation loading helper
- Language-switch router
- HTML templates that call translation keys
Running the generated app
After generation, change into the generated app folder (the folder named by app_name), install dependencies, and run with uvicorn.
Typical flow:
cd my_app
uv sync
uv run uvicorn main:app --reload
Default database is SQLite at app.db. An admin user is created on first startup.
Default admin credentials:
- Email: admin@admin.com
- Password: admin
Customizing output
Edit templates in fsgenerator/templates/ to change generated code shape:
- API behavior
- SQLAlchemy model patterns
- HTML layout and UX
- Authentication flow
- Dependency wiring
- CSS styling (static/style.css)
- i18n runtime helper
After template changes, run the generator again.
Known limitations
- The generator focuses on CRUD scaffolding.
- many_to_many and one_to_many relations are parsed but are not fully emitted as SQLAlchemy relationship collections in current templates.
- primary_key inside field definitions is parsed but global ID generation from app_config.id_type is used.
- No migration generation is included (for example, Alembic).
Troubleshooting
- Error about unknown relation target:
- Ensure each relation entity points to an existing entity JSON file name.
- Missing app_config.json:
- Ensure the target input folder contains app_config.json.
- Unexpected type behavior:
- Check mappings in fsgenerator/type_mapping.py.
- Wrong output folder:
- Check app_name in app_config.json.
- Delete errors showing raw JSON:
- Entity delete endpoints display errors on the list page when a record has dependent relations.
Version
Current version: 0.5.0
Metadata
Release files for fsgenerator 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fsgenerator-0.6.0.tar.gz | 34.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fsgenerator-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 81.5 kB
Release files / fsgenerator-0.6.0.tar.gz
| Download URL | fsgenerator-0.6.0.tar.gz |
|---|---|
| Size | 34.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e2feea3ecd4d0a57264f49a943a9d14d35eb6ace8f68d6370f5c34d3e5e1e609
|
|
BLAKE2b-256 checksum How to use checksums |
5d326d93c758eb64876d0f5970bcee5f51fa94fd4911bbfd7f0e11ad7fb6eede
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / fsgenerator-0.6.0-py3-none-any.whl
| Download URL | fsgenerator-0.6.0-py3-none-any.whl |
|---|---|
| Size | 47.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a089a6f5f3efbded10c94805b15a596835097c5bea1d13c678295819aeec3d49
|
|
BLAKE2b-256 checksum How to use checksums |
abf16fb9ad7aaa5d6a6254889a3cb81ed8a8d229d758357dcf220da626b1309b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|