Files
OSIT-AE-API-FastAPI/documentation/ARCH__V3_DEVELOPMENT_STANDARDS.md
Scott Idem c7335bbc3e fix(event_session): restore event_presentation/presenter_li_qry_str fields
These fields from v_event_session_w_file_count were lost during the v1/v2
-> v3 migration. Added to Event_Session_Base model and to searchable_fields
in the event_session object definition.

Fields are only available via the alt view (v_event_session_w_file_count).
To search: use ?view=alt on the nested search endpoint.
To retrieve: use ?inc_file_count=true on the GET endpoint.

Also:
- Updated ARCH__V3_DEVELOPMENT_STANDARDS.md: expanded Field Evolution
  Checklist with alt-view field rules, Docker restart requirement, and
  documented the ?view= parameter as a live (not proposed) feature.
- Updated TODO__Agents.md: marked migration gap audit as complete.
- Added regression test to test_e2e_v3_search_engine.py.
2026-05-15 12:32:26 -04:00

5.2 KiB

Aether V3 Development Standards & Strategy

This document serves as the master guide for the Aether API V3. It combines core architectural principles with the finalized infrastructure standards established in January 2026.

1. Core Principles

  • id_random Primary: id_random (URL-safe string) is the only identifier exposed to clients. Internal integer id is a private implementation detail.
  • Singular naming: All object types and prefixes use singular form (e.g., journal, not journals).
  • Inheritance: All models must inherit from CoreObject to ensure consistent base fields.
  • Separation of Concerns: Business logic lives in app/methods/, CRUD helpers in app/lib_sql_crud.py, and routing in app/routers/.

2. Infrastructure Standards

Finalized Jan 15, 2026, to ensure boot stability.

Application Entry Point (app/main.py)

  • Registry Pattern: All routers are registered via app/routers/registry.py.
  • Lifespan Management: All startup tasks (logging setup, DB bootstrap, engine refresh) MUST reside within the @contextlib.asynccontextmanager lifespan.
  • No Top-Level Logic: No SQL queries or heavy initialization should execute at the module level.

Database Layering

  • lib_sql_core.py: The foundational "Source of Truth" for the SQLAlchemy engine and global db connection.
  • lib_sql_crud.py: High-level logic for sql_insert, sql_select, etc.
  • db_sql.py: A backward-compatible facade. code should import from here.

Logging

  • Explicit Setup: setup_logging(settings) must be called during the lifespan startup.
  • lib_log_v3.py: New home for logging configuration and the logger_reset decorator.

3. V3 CRUD Strategy

URL Structure

  • Top-Level: /v3/crud/{obj_type}/
  • Nested: /v3/crud/{parent_type}/{parent_id_random}/{obj_type}/ (Enforces parent ownership).

Search API

  • POST Based: Complex filtering is handled via POST /search with a JSON body containing and, or, and not logic.
  • Hybrid Filtering: (Proposed) Query parameters should append simple standard filters (e.g., ?enabled=true) to the complex body logic.

Field Evolution Checklist

When a table or view gains, loses, or renames fields, keep the API contract and search registry in sync:

  1. Update the Pydantic model in app/models/ first so CRUD serialization matches the new shape.
  2. Update the SQL view or table projection so GET and SEARCH responses actually return the field.
  3. Update searchable_fields in app/object_definitions/ only for fields that should be searchable.
  4. Add write-only, virtual, or view-only fields to fields_to_exclude_from_db when they must not be persisted.
  5. Run the schema/search E2E tests that cover the object type before handing the change off.
  6. Restart the Docker API containers (docker compose restart ae_api) — Python file changes inside containers are not picked up until restart.

For archive_content, the public field set now includes external_id and code, and future additions should follow the same order of operations.

Alt-view fields (fields only in tbl_alt)

Some objects have a richer alternate SQL view (tbl_alt) that adds JOINed/computed columns absent from the default view (tbl_default). For example, event_session uses v_event_session_w_file_count as its alt view (triggered by ?view=alt on search, or ?inc_file_count=true on GET).

  • Fields from tbl_alt must still be declared in the Pydantic model and in searchable_fields — Pydantic strips undeclared fields, and the search whitelist rejects unknown field names regardless of the view.
  • When adding such a field, add a comment noting which view provides it (e.g., # from v_event_session_w_file_count).
  • Searching by an alt-view field on the default endpoint returns 400 Unknown column — this is correct behaviour. Clients must pass ?view=alt to use those fields in a search.
  • Known alt-view fields restored May 2026: event_presentation_li_qry_str, event_presenter_li_qry_str (event_session); account_name, account_code, and related convenience fields (site_domain).

Response Views (?view= parameter)

  • The nested search router (api_crud_v3_nested.py) already supports ?view=<key> to switch between registered views. view=default uses tbl_default; view=alt uses tbl_alt; additional named views can be added to the object registry as tbl_<name> / mdl_<name>.
  • Flat search (api_crud_v3.py) does not yet support ?view= — it always uses tbl_default.

4. Stability Rules

  1. Baby Step Testing: Restart Docker and verify root health after every modular change.
  2. Avoid Shadowing: Never name a module part of the app. package the same as a common instance variable (e.g., avoid app.middleware package if you use app = FastAPI()).
  3. Deferred Imports: Use from app.db_sql import ... inside functions in library modules to prevent circular dependency traps.
  4. Model changes require container restart: Editing Python files on the host does not hot-reload inside Docker. Always run docker compose restart ae_api after model or object-definition changes, then re-run E2E tests.