- Add bible.git as submodule at bible/ - Rename bible/ → bible-local/ (project-specific architecture) - Update CLAUDE.md to reference both bible/ and bible-local/ - Add AGENTS.md for Codex with same structure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.3 KiB
4.3 KiB
07 — Development
Commands
# Run (dev)
go run ./cmd/qfs
make run
# Build
make build-release # Optimized build with version info
CGO_ENABLED=0 go build -o bin/qfs ./cmd/qfs
# Cross-platform build
make build-all # Linux, macOS, Windows
make build-windows # Windows only
# Verification
go build ./cmd/qfs # Must compile without errors
go vet ./... # Linter
# Tests
go test ./...
make test
# Utilities
make install-hooks # Git hooks (block committing secrets)
make clean # Clean bin/
make help # All available commands
Code Style
- Formatting:
gofmt(mandatory) - Logging:
slogonly (structured logging to the binary's stdout/stderr). Noconsole.logor any other logging in browser-side JS — the browser console is never used for diagnostics. - Errors: explicit wrapping with context (
fmt.Errorf("context: %w", err)) - Style: no unnecessary abstractions; minimum code for the task
Guardrails
What Must Never Be Restored
The following components were intentionally removed and must not be brought back:
- cron jobs
- importer utility
- admin pricing UI/API
- alerts
- stock import
Configuration Files
config.yaml— runtime user file, not stored in the repositoryconfig.example.yaml— the only config template in the repo
Sync and Local-First
- Any sync changes must preserve local-first behavior
- Local CRUD must not be blocked when MariaDB is unavailable
Formats and UI
- CSV export: filename must use project code (
project.Code), not project name Format:YYYY-MM-DD (ProjectCode) ConfigName Article.csv - Breadcrumbs UI: names longer than 16 characters must be truncated with an ellipsis
Architecture Documentation
- Every architectural decision must be recorded in
bible/ - The corresponding Bible file must be updated in the same commit as the code change
- On every user-requested commit, review and update the Bible in that same commit
Common Tasks
Add a Field to Configuration
- Add the field to
LocalConfigurationstruct (internal/models/) - Add GORM tags for the DB column
- Write a SQL migration (
migrations/) - Update
ConfigurationToLocal/LocalToConfigurationconverters - Update API handlers and services
Add a Field to Component
- Add the field to
LocalComponentstruct (internal/models/) - Update the SQL query in
SyncComponents() - Update the
componentRowstruct to match - Update converter functions
Add a Pricelist Price Lookup
// Modern pattern
price, found := s.lookupPriceByPricelistID(pricelistID, lotName)
if found && price > 0 {
// use price
}
Known Gotchas
CurrentPriceremoved from components — any code using it will fail to compileHasPricefilter removed —component.go ListComponentsno longer supports this filter- Quote calculation: always offline-first (SQLite); online path is separate
- Items JSON: prices are stored in the
itemsfield of the configuration, not fetched from components - Migrations are additive: already-applied migrations are skipped (checked by
idinlocal_schema_migrations) SyncedAtremoved: last component sync time is now inapp_settings(key=last_component_sync)
Debugging Price Issues
Problem: quote returns no prices
- Check that
pricelist_idis set on the configuration - Check that pricelist items exist:
SELECT COUNT(*) FROM local_pricelist_items - Check
lookupPriceByPricelistID()inquote.go - Verify the correct source is used (estimate/warehouse/competitor)
Problem: component sync not working
- Components sync as metadata only — no prices
- Prices come via a separate pricelist sync
- Check
SyncComponents()and the MariaDB query
Problem: configuration refresh does not update prices
- Refresh uses the latest estimate pricelist by default
- Latest resolution ignores pricelists without items (
EXISTS local_pricelist_items) - Old prices in
config.itemsare preserved if a line item is not found in the pricelist - To force a pricelist update: set
configuration.pricelist_id - In configurator,
Автоmust remain auto-mode (runtime resolved ID must not be persisted as explicit selection)