7.9 KiB
7.9 KiB
S4.2 — Relational schema foundation
Date: 2026-08-15 Status: implementation + local verification complete; dependency lock wired; offline-dialect remediation verified; code/schema/dependency review passed; PostgreSQL runtime/cutover blocked
Scope actually changed
backend/requirements.txt— pinned direct runtime/test dependencies, including SQLAlchemy, Alembic, and psycopg PostgreSQL driver.backend/requirements.lock.txt— uv-generated transitive lock with hashes; Docker and backend CI install this file with--require-hashes.backend/app/config.py— optionalDATABASE_URLconfiguration.backend/app/db.py— engine/session helpers with SQLite foreign-key enforcement.backend/app/models/entities.pyandbackend/app/models/__init__.py— tenant-safe relational entities for organizations, users, groups, personas, sessions, messages, and audit events.backend/alembic.ini,backend/migrations/env.py, andbackend/migrations/versions/0001_initial_schema.py/0002_audit_actor_tenant_check.py— portable migration wiring and audit tenant hardening.backend/tests/test_db_schema.py— schema, tenant-FK, one-shot uniqueness, and migration up/down contract tests.- Generated
frontend/dist/artifacts removed from the worktree; the repository policy is source-only frontend plus reproducible Docker/CI builds.
Tests written first
test_schema_contains_core_tables_and_tenant_keys: failed before implementation becauseapp.db/Alembic were unavailable; passes after implementation.test_constraints_preserve_tenant_links_and_attempt_uniqueness: initially exposed SQLite FK fixture configuration and ORM insert ordering; after fixing the fixture it passed, then a RED regression was added for cross-org audit actors.- Cross-org audit actor regression: failed before the composite actor/org FK; passes after the model and migration were updated together.
- Partial-null audit actor regression: failed before
ck_audit_actor_requires_org; passes after the check constraint was added to ORM metadata and migration0002. - Raw SQL default regression: failed against
Base.metadata.create_allbefore modelserver_defaultvalues were aligned with Alembic; passes after alignment. test_alembic_migration_up_and_down: failed before Alembic was installed; passes after the migration foundation was added.- Root-CWD migration regression: failed with CWD-relative
script_location; passes after using%(here)spaths inalembic.ini.
Verification evidence
cd backend && ./.venv/bin/python -m pytest tests/test_db_schema.py -q→8 passedafter the offline unsupported-dialect regression was added.cd /Users/kunthawat/Gitea/Sales Trainer && backend/.venv/bin/python -m pytest -q→209 passedafter the offline guard remediation.- Clean Python 3.11 temporary venv installed
backend/requirements.lock.txtwithpip --require-hashes; full backend suite →195 passed in 38.95s. - uv regenerated the lock from pinned requirements:
42 packages,810 lines; normalized package-entry comparison was identical. - Dockerfile and
.gitea/workflows/ci.ymlnow install the hash-locked requirements file. cd backend && for script in scripts/test_*.py; do ./.venv/bin/python "$script"; done→12 executable scripts passed.- Temporary SQLite
alembic upgrade head+alembic check+alembic downgrade base→ passed after the JSON-parity and audit actor FK changes. - Alembic upgrade/check/downgrade → passed from both repository-root and
backend/CWDs, including migration0002. - Bundled schema parity probe found only the expected
alembic_versionbookkeeping table difference; MySQL partial-index weakening is now prevented on both online and offline Alembic paths by the shared dialect guard and regression tests. python -m compileall -q app migrations tests→ passed.git diff --check→ passed.- Added-line static security scan →
added_line_findings=[]. ruffandmypywere not installed in the local environment; both were skipped and not represented as passing.- Full-stack contract audit → API contract clean; no committed/generated
frontend/distremains, so the Docker/CI build path is unambiguous.
Security/data notes
- Secrets exposed: no; scans returned no private keys, token literals, shell execution, or unsafe deserialization patterns in added lines.
- Production data touched: no; all schema tests use temporary SQLite databases.
- Migration/rollback: schema migration up/down verified on temporary SQLite. PostgreSQL execution, importer, parity checks, rollback rehearsal, and runtime repository cutover remain unverified.
pip checkstill reports a pre-existing shared-venv conflict:alibabacloud-tea-openapi 0.4.4requirescryptography<47, while the environment hascryptography 50.0.0. This is not caused by the S4.2 requirements and was not changed.
Review findings resolved locally
- Nullable audit tenant link: fixed with
ck_audit_actor_requires_orgin ORM metadata and migration0002. - CWD-relative Alembic paths: fixed with
%(here)s/migrationsand%(here)sprepend_sys_path; config URL now delegates todatabase_url(). - ORM/migration default drift: model columns now carry matching server defaults while retaining ORM defaults.
- Dependency resolution drift: direct requirements are pinned and all transitive artifacts are hash-locked; Docker/CI no longer resolve an unbounded requirements file.
- Unsupported partial-index dialect: shared
validate_database_url()is used bycreate_db_engine()and Alembic offline URL resolution, so MySQL is rejected before connection or SQL rendering and cannot silently weaken non-preview attempt uniqueness.
Remaining blockers
- The earlier reviewer
deleg_e672880areturned valid five-key JSON withpassed=truefor the schema/dependency packet; its final closure was held after the later exact-current offline-path finding fromdeleg_c2e728d8. - The offline-path blocker is remediated and verified locally; fresh exact-current reviewer
deleg_40e8edf9returned valid five-key JSON withpassed=true, empty blocking arrays, and five non-blocking suggestions. - Docker is unavailable on this Mac; no image build or container smoke was claimed.
- PostgreSQL service, JSON importer, repository wiring, Redis/DB rate-limit store, real-provider QA, and production operation remain pending.
- Non-blocking reviewer hardening suggestions remain: immutable CI action/base-image pinning, isolated CI-only credentials, preserving audit attribution semantics on actor deletion, and broader upgraded-database parity assertions.
Exact next action
- Continue S4.3 one aggregate at a time; do not delete JSON stores or wire production cutover until importer/parity/rollback gates pass.
- Resolve the remaining legacy security and S4.3 independent-review gates against the exact current tree.
- Keep PostgreSQL, Docker, Redis, real-provider QA, and restricted live-operation gates explicitly separate from local approval.
Independent review verdict
deleg_e672880a— valid schema/dependency review;passed=true;security_concerns=[];logic_errors=[]; combined with the post-remediation review below.deleg_c2e728d8— valid exact-current review;passed=falsefor the offline unsupported-dialect path; remediation is recorded in2026-08-15-s4-3-offline-dialect-remediation.md.deleg_40e8edf9— fresh exact-current post-remediation review;passed=true;security_concerns=[];logic_errors=[].- Non-blocking suggestions: add explicit before-commit and immutable-field regression assertions, document global username/email uniqueness intent, map duplicate-key errors, and run live PostgreSQL smoke before cutover.
- This closes the code/schema/dependency review scope only. It is not PostgreSQL, Docker, production cutover, or deployment approval.
Files explicitly not to touch for this packet
.env- credential helpers or production configuration
- unrelated product/runtime routes
- JSON stores and production data