- Overhauled README.md to serve as a unified system index and WIP tracker. - Standardized documentation filenames (ARCH__, GUIDE__, PLAN__) for better discoverability. - Archived completed project plans and scopes. - Fixed regressions in unit tests (errors, models, email) caused by V3 architectural updates. - Ensured unit tests remain non-destructive and environment-independent via mocking.
6.1 KiB
6.1 KiB
Aether API V3 CRUD: Architecture and Learnings
This document summarizes the development of the V3 CRUD API, the architectural choices made, and the lessons learned during the process.
1. V3 CRUD Architecture
The V3 CRUD API (/v3/crud/) is designed to run in parallel with legacy V1 and V2 endpoints. It introduces a hierarchical, nested URL structure and leverages modern FastAPI features for better maintainability and performance.
Key Features:
- Nested URL Structure: Enforces parent-child relationships (e.g.,
/v3/crud/site/{site_id}/site_domain/). - Granular Dependencies: Instead of a monolithic common parameters object, V3 uses specialized, reusable dependencies from
app/lib_general_v3.py:AccountContext: Resolves account ID with clear precedence (Header > Query Token > Bypass Header).PaginationParams: Standardizeslimitandoffset.StatusFilterParams: Handlesenabledandhiddenstatus filtering.SerializationParams: Controls Pydantic serialization options (by_alias,exclude_unset).DelayParams: Facilitates optional latency simulation for testing.
- Non-blocking Delay: Uses
await asyncio.sleep()to simulate network latency without blocking the Gunicorn worker's event loop. - Data-Driven Configuration: Uses the modern format in
app/ae_obj_types_def.pyto map objects to tables and models. - Advanced Search (POST): Supports complex, nested filtering via
POST /v3/crud/{obj_type}/search.- Recursive AND/OR logic.
- Full operator support:
eq,ne,gt,gte,lt,lte,in,is_null,is_not_null,like,contains,startswith,endswith. - Safe parameterization using unique generated names (e.g.,
:sp_1) to prevent collisions.
2. Backward Compatibility Strategy
To ensure that the introduction of V3 doesn't break legacy V1 and V2 endpoints:
- Parallel Routes: All V3 logic is isolated in
app/routers/api_crud_v3.py. - Hybrid Configuration: The
obj_type_kv_lidictionary inapp/ae_obj_types_def.pyhas been updated to include both modern keys (e.g.,tbl,mdl) and legacy keys (e.g.,table_name,base_name). This allows V2 endpoints to continue functioning normally while V3 endpoints use the refined structure. - Stable Core Imports: Core modules like
app/lib_general.pyandapp/models/response_models.pyhave been refactored to maintain their existing exports (log,logging,mk_resp) while internally adopting more robust module-level logging.
3. Learnings and Best Practices
Logging and Startup Stability
- Isolate Loggers: Modules should instantiate their own module-level loggers (
logging.getLogger(__name__)) rather than importing a global instance. This breaks circular dependencies and improves traceability. - Robust Configuration: Logging configuration (
dictConfig) should be wrapped intry...exceptto prevent application crashes due to environment issues (e.g., missing log directories in Docker). - Explicit Imports: Always use
import logging.configbefore callinglogging.config.dictConfigto ensure the module is fully initialized.
FastAPI and Pydantic
- Dependency Injection: Use
response: Responseas a type hint for standard injection. AvoidDepends(Response)as it is not a valid dependency provider and can cause router initialization failures. - Python Parameter Order: In function signatures, non-default arguments (like
response: Response) must precede arguments with default values orDepends(). - Async Concurrency: Use
asyncio.sleep()instead oftime.sleep()in async endpoints. Blocking the event loop in a high-concurrency environment leads to worker timeouts and502 Bad Gatewayerrors. - Pydantic Compatibility: Ensure all new models and utility functions remain compatible with Pydantic v1.10 until a full project-wide migration to v2 is planned. Avoid V2-only features like
computed_fieldormodel_validator.
4. Current Migration Status
The following objects have been migrated to the modern V3 configuration and are supported by the V3 API:
journal,journal_entrysite,site_domainaccount,account_cfgaddress,contactorder,order_lineorganization,pagedata_store,activity_logarchive,archive_contenthosted_file,post,post_commentperson,userlu_country,lu_country_subdivision,lu_time_zone
5. Security and Data Isolation
Implemented in Jan 2026, the V3 architecture enforces strict data isolation and role-aware authorization.
Role-Aware Authorization (AuthContext)
- Deferred User Lookup: When a JWT is provided, the API performs a deferred database lookup via
load_user_objto populateadministrator,manager, andsuperflags. - Role Scoping: These flags are used to bypass account isolation for support and system maintenance tasks.
Multi-Tenant Isolation
- Forced Account Filtering: For all non-super users, the API automatically injects an
account_idfilter into every list and search query. This is enforced at the SQL level viaapply_forced_account_filter. - Post-Retrieval Verification: Single object retrievals (
GET), updates (PATCH), and deletions (DELETE) include a secondary ownership check (check_account_access). If a user attempts to access an ID belonging to another account, they receive a403 Forbiddenresponse. - Hierarchical Verification: Child/Nested endpoints verify the ownership of the parent object before allowing operations on children, preventing cross-tenant "sideways" traversal.
- Creation Guard: When creating records (
POST), the user'saccount_idis automatically forced onto the new record, preventing a user from creating data for another account.
Bypass and Utility Access
- X-No-Account-ID: A specialized header used by development utilities and administrative scripts to bypass standard account isolation. This header grants
superpermissions and should only be used in trusted internal environments. - JWT Query Parameter: Supported for direct file downloads and sharing links where custom headers cannot be provided.