Skip to content

Commit e41ac4c

Browse files
docs: update complete user example and quickstart documentation for manage.py integration
- Replace references from `main.py` to `manage.py` as the CLI entry point. - Enhance configuration setup by introducing `customize()` method for service-specific defaults. - Update project layout to reflect the new structure and clarify the organization of files. - Add command options for running the application in the quickstart guide.
1 parent 788145b commit e41ac4c

2 files changed

Lines changed: 109 additions & 45 deletions

File tree

docs/getting-started/complete_user_example.md

Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,48 @@ description: End-to-end ArchiPy application — entities, DTOs, adapters, reposi
66
# Complete User Example
77

88
This page walks through every layer of a real ArchiPy application for a **User** domain, from the database
9-
entity all the way to the FastAPI endpoint and `main.py`. Each section corresponds to one layer in the
9+
entity all the way to the FastAPI endpoint and `manage.py`. Each section corresponds to one layer in the
1010
[four-layer architecture](../getting-started/concepts.md).
1111

1212
---
1313

1414
## Project Layout
1515

1616
```
17-
my_app/
18-
├── configs/
19-
│ ├── app_config.py
20-
│ └── containers.py
21-
├── models/
22-
│ ├── dtos/
17+
project-root/
18+
├── my_app/
19+
│ ├── configs/
20+
│ │ ├── app_config.py
21+
│ │ └── containers.py
22+
│ ├── models/
23+
│ │ ├── dtos/
24+
│ │ │ └── user/
25+
│ │ │ ├── domain/v1/user_dtos.py # versioned — cross service boundary
26+
│ │ │ └── repository/user_dtos.py # internal — never versioned
27+
│ │ ├── entities/user.py
28+
│ │ └── errors/user_errors.py
29+
│ ├── repositories/
2330
│ │ └── user/
24-
│ │ ├── domain/v1/user_dtos.py # versioned — cross service boundary
25-
│ │ └── repository/user_dtos.py # internal — never versioned
26-
│ ├── entities/user.py
27-
│ └── errors/user_errors.py
28-
├── repositories/
29-
│ └── user/
30-
│ ├── adapters/
31-
│ │ ├── user_db_adapter.py
32-
│ │ └── user_cache_adapter.py
33-
│ └── user_repository.py
34-
├── logics/
35-
│ └── user/
36-
│ ├── user_registration_logic.py
37-
│ └── user_query_logic.py
38-
├── services/
39-
│ └── user/v1/user_service.py
40-
└── main.py
31+
│ │ ├── adapters/
32+
│ │ │ ├── user_db_adapter.py
33+
│ │ │ └── user_cache_adapter.py
34+
│ │ └── user_repository.py
35+
│ ├── logics/
36+
│ │ └── user/
37+
│ │ ├── user_registration_logic.py
38+
│ │ └── user_query_logic.py
39+
│ └── services/
40+
│ └── user/v1/user_service.py
41+
42+
├── features/ # BDD acceptance tests (behave)
43+
│ ├── user_registration.feature
44+
│ ├── steps/
45+
│ │ └── user_steps.py
46+
│ ├── scenario_context.py
47+
│ ├── scenario_context_pool_manager.py
48+
│ └── environment.py
49+
50+
└── manage.py # CLI entry point — click commands
4151
```
4252

4353
---
@@ -47,17 +57,23 @@ my_app/
4757
```python
4858
# configs/app_config.py
4959
from archipy.configs.base_config import BaseConfig
60+
from archipy.configs.environment_type import EnvironmentType
5061

5162

5263
class AppConfig(BaseConfig):
5364
"""Application-specific configuration.
5465
5566
All ArchiPy sections (REDIS, POSTGRES, FASTAPI, …) are inherited from BaseConfig.
56-
Add custom fields below.
67+
Override `customize` to apply app-specific defaults after loading.
5768
"""
5869

59-
APP_NAME: str = "my-service"
60-
DEBUG: bool = False
70+
def customize(self) -> None:
71+
"""Apply app-specific configuration overrides."""
72+
super().customize()
73+
self.FASTAPI.PROJECT_NAME = "my-service"
74+
self.FASTAPI.SERVE_HOST = "0.0.0.0" # noqa: S104
75+
self.FASTAPI.SERVE_PORT = 8000
76+
self.FASTAPI.RELOAD = self.ENVIRONMENT == EnvironmentType.LOCAL
6177

6278

6379
config = AppConfig()
@@ -653,27 +669,55 @@ def create_router(container: UserContainer) -> APIRouter:
653669

654670
---
655671

656-
## Entry Point
672+
## Entry Point: `manage.py`
657673

658674
```python
659-
# main.py
660-
from archipy.helpers.utils.app_utils import AppUtils
675+
# manage.py
676+
import click
677+
import uvicorn
661678

662-
import configs.app_config # noqa: F401 — importing triggers BaseConfig.set_global
679+
import configs.app_config # noqa: F401 — triggers BaseConfig.set_global
680+
from archipy.configs.base_config import BaseConfig
681+
from archipy.helpers.utils.app_utils import AppUtils
663682
from configs.containers import UserContainer
664683
from services.user.v1.user_service import create_router as create_user_v1_router
665684

666-
user_container = UserContainer()
667685

668-
app = AppUtils.create_fastapi_app()
669-
app.include_router(create_user_v1_router(user_container))
686+
def create_app():
687+
"""Create and configure the FastAPI application."""
688+
user_container = UserContainer()
689+
app = AppUtils.create_fastapi_app()
690+
app.include_router(create_user_v1_router(user_container))
691+
return app
670692

671-
if __name__ == "__main__":
672-
import uvicorn
673-
from archipy.configs.base_config import BaseConfig
674693

694+
@click.group()
695+
def cli():
696+
"""Management commands for my_app."""
697+
698+
699+
@cli.command()
700+
@click.option("--host", default=None, show_default=True, help="Bind host (defaults to FAST_API.SERVE_HOST).")
701+
@click.option("--port", default=None, type=int, show_default=True, help="Bind port (defaults to FAST_API.SERVE_PORT).")
702+
@click.option("--reload/--no-reload", default=None, help="Enable auto-reload (defaults to FAST_API.RELOAD).")
703+
def run(host: str | None, port: int | None, reload: bool | None) -> None:
704+
"""Start the FastAPI development server."""
675705
config = BaseConfig.global_config()
676-
uvicorn.run(app, host="0.0.0.0", port=8000) # noqa: S104
706+
serve_host = host or config.FAST_API.SERVE_HOST
707+
serve_port = port or config.FAST_API.SERVE_PORT
708+
serve_reload = config.FAST_API.RELOAD if reload is None else reload
709+
uvicorn.run("manage:create_app", factory=True, host=serve_host, port=serve_port, reload=serve_reload)
710+
711+
712+
if __name__ == "__main__":
713+
cli()
714+
```
715+
716+
Run the server with:
717+
718+
```bash
719+
python manage.py run
720+
python manage.py run --port 9000 --reload
677721
```
678722

679723
---

docs/getting-started/quickstart.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ uv add "archipy[redis,cache]"
3434

3535
## Step 3 — Define the Configuration
3636

37-
Create a configuration class that extends `BaseConfig`. Add only the fields your service needs:
37+
Create a configuration class that extends `BaseConfig`. Override `customize()` to apply service-specific defaults after all sources are loaded:
3838

3939
```python
4040
# configs/app_config.py
4141
import logging
42+
4243
from archipy.configs.base_config import BaseConfig
44+
from archipy.configs.environment_type import EnvironmentType
4345

4446
logger = logging.getLogger(__name__)
4547

@@ -48,11 +50,14 @@ class AppConfig(BaseConfig):
4850
"""Service-level configuration.
4951
5052
All ArchiPy config sections (REDIS, FASTAPI, etc.) are inherited.
51-
Add custom fields below.
53+
Override `customize` to set service-specific defaults.
5254
"""
5355

54-
APP_NAME: str = "my-service"
55-
DEBUG: bool = False
56+
def customize(self) -> None:
57+
"""Apply service-specific configuration overrides."""
58+
super().customize()
59+
self.FASTAPI.PROJECT_NAME = "my-service"
60+
self.FASTAPI.RELOAD = self.ENVIRONMENT == EnvironmentType.LOCAL
5661

5762

5863
config = AppConfig()
@@ -111,21 +116,36 @@ name = get_user_name("42")
111116
## Step 6 — Run the App
112117

113118
```python
114-
# main.py
119+
# manage.py
115120
import logging
121+
122+
import click
123+
116124
import configs.app_config # noqa: F401 — triggers BaseConfig.set_global
117125
from logics.user_logic import get_user_name
118126

119127
logging.basicConfig(level="INFO")
120128
logger = logging.getLogger(__name__)
121129

122-
if __name__ == "__main__":
130+
131+
@click.group()
132+
def cli():
133+
"""Management commands for my_service."""
134+
135+
136+
@cli.command()
137+
def run() -> None:
138+
"""Run a quick cache demonstration."""
123139
logger.info(get_user_name("42"))
124140
logger.info(get_user_name("42")) # returns from cache
141+
142+
143+
if __name__ == "__main__":
144+
cli()
125145
```
126146

127147
```bash
128-
uv run main.py
148+
python manage.py run
129149
```
130150

131151
You should see:

0 commit comments

Comments
 (0)