Cline a829d6e8c6 feat: catalog shared contracts (Tasks 1-4)
Task 1: Establish catalog identity and atomic file ownership
- CatalogService, CatalogServiceInterface, ModelMetadata DTO
- PdoCatalogRepository with atomic operations, savepoint support
- FOR UPDATE file locks in ascending order, FOR NO KEY UPDATE for metadata
- FK-compatible lock composition documented (spec §6)

Task 2: M3 import & indexing engine delivery layer
- ImportService, ImportWorker with durable collision handling
- SpaceChecker, StreamingHasher, VerifiedCopier, StlValidator
- FileEnumerator, LocalFilesystem, PathSafety
- Console command wiring via ContainerWiringTest

Task 3: Importer integration and repair
- LegacyGuessedImportGroupingAdapter isolates first-directory guessing
- ImportService uses adapter; ImportWorker uses CatalogServiceInterface
- Null owners remain null; DomainException mapped to CATALOG_CONFLICT
- SQL failure after registration/path update with caller sentinel rollback

Task 4: PostgreSQL contention evidence and bounded acceptance
- 6 new PostgresCatalogContractsTest cases with independent sessions
- Generated schemas, 250ms lock timeouts, 5s statement timeouts
- Ascending file locks, FOR SHARE contention, stale-owner rejection
- Rollback/retry, nested transaction survival, root creation contention
- Negative controls: replay FOR UPDATE removal (11 failures), metadata FOR UPDATE (4 FK KEY SHARE timeouts)
- Fresh Docker PostgreSQL 17 / PHP 8.4.26: 473 tests, 2718 assertions, 10 skips, exit 0

All local: 474 tests, 2347 assertions, 54 skips, foundation/lint clean.
2026-10-13 19:41:03 -05:00
2026-10-10 12:44:39 -05:00

MeshVault

MeshVault is a self-hosted 3D model library being built as a Docker service. It catalogs logical models containing STL parts, images and supplementary documents.

Status: The development stack, Phinx database migrations, and initial CLI import engine are implemented. Imports have scanning, STL validation, streaming hashes, verified copying, durable jobs, and repository integration. PostgreSQL-specific integration tests exercise production migrations and two-session locking.

This is not yet a usable catalog application or a completed import workflow. The HTTP surface is a landing page; explicit grouping confirmation, complete crash/retry recovery, catalog editing, and browse/search screens remain unfinished. M2/M3 issue acceptance is partial, not implied by the existence of schema or engine code. See the acceptance review, the development stack setup, and PostgreSQL testing. Do not deploy as a production service.

Planned MVP

  • Managed imports copy existing collections without changing their originals. Read-only source directories are supported; the managed destination must be writable.
  • Physical folder browsing and management mirror the managed directory tree.
  • Imports provide a pre-scan, progress and per-file failure reasons.
  • Logical models support multiple files, categories, tags, notes, source URLs and uploaded thumbnails, with name/tag search and downloads.
  • Catalog removal deletes database records only, retaining physical files.
  • Missing files, changed content and exact duplicates are visible for user resolution. There is no automatic deletion or merging.

Date added records entry into MeshVault, not filesystem creation. File modification times and sizes are separate metadata; MVP has no separate creation-date field. Changed content is flagged Updated, with user acknowledgement re-baselining its hash. No historical contents are preserved: an external overwrite cannot be undone by detecting it. Backups must include PostgreSQL metadata, library files and uploaded media as a consistent set using standard database/filesystem tools.

Other mesh formats, generated thumbnails, 3D viewing, watching, versioning, printer management, external imports, AI and multi-user libraries are outside MVP.

Architecture and decisions

Docker, PostgreSQL and PHP application logic; PHP-rendered templates with Tailwind CSS and browser JavaScript. Node runs inside an assets container for deterministic locked builds and watch; no host Node is required. Slim 4, PHP-DI and Monolog are installed, locked and wired. HTTP, configuration, logging and task wrappers are verified on the remote development host.

Accepted decisions: managed storage (#1), dates (#2), and changed files (#3). Tracking lives in issues. Local planning notes and ADR copies are deliberately not versioned.

Repository layout

Directory Responsibility
src/ PHP application and domain code
public/ Future HTTP document root and generated browser assets
db/migrations/ Ordered PostgreSQL schema migrations
docker/ Development container definitions, configuration and setup
assets/ Source assets, including the project icon
tests/ Automated checks and future application fixtures/tests

Directory READMEs describe boundaries; they are not application implementations.

Development checks

The only host prerequisite is Docker Compose v2+ with Linux containers. All PHP and Node tooling runs inside containers.

# Start the stack (builds images if needed)
./dev.sh up
# Or on Windows: .\dev.ps1 up

# Run checks inside the app container
./dev.sh test
./dev.sh lint

# Build minified assets inside the assets container
./dev.sh assets
# Watch for template changes
./dev.sh watch

composer test and composer lint also work on a host with PHP 8.3+ and Composer 2. composer audit checks locked PHP dependencies. migrate and seed are available via ./dev.sh (M2 #12).

Asset builds use a locked package-lock.json inside a container; host Node is not required. The generated public/build/app.css is served statically by nginx.

Configuration and logging library

MeshVault\Config\AppConfig::fromEnvironment(array $environment) accepts explicit string values; supported keys, defaults and validation rules are in .env.example. Native PHP does not read .env: export the variables through your shell/process manager, then pass getenv() to the factory after requiring vendor/autoload.php. Compose injects the environment and the PHP entrypoint validates configuration as the runtime user before starting FPM. The library never creates or chmods library roots.

Readonly properties: environment, libraryPath, dbHost, dbPort, dbName, dbUser, dbPassword, logLevel. Configuration JSON/debug/serialization is redacted; serialized configuration cannot be restored. Read credentials only at their point of use: do not cast configuration to arrays or log credentials/messages containing them. This is not a general-purpose sanitizer for arbitrary caller-supplied secrets.

MeshVault\Logging\LoggerFactory::create($config) returns a PSR-3 logger writing newline-delimited JSON to stdout at the configured level. forJob($logger, $jobId) returns an independent scope; its job_id takes precedence over caller context, while other context is retained. Re-scoping replaces the job ID; the base logger and other jobs are unchanged. FPM forwarding was exercised during M1 runtime validation.

License

MeshVault is licensed under GNU AGPL version 3 only (AGPL-3.0-only). See LICENSE for the complete terms, including source availability requirements for modified versions used interactively over a network.

S
Description
No description provided
Readme AGPL-3.0
676 KiB
0 Stars 1 Watchers 0 Forks
Languages
PHP 98.3%
Shell 0.8%
PowerShell 0.6%
Dockerfile 0.3%