555 lines
24 KiB
Markdown
555 lines
24 KiB
Markdown
# AGENTS.md
|
|
|
|
## Project Goal
|
|
|
|
Maintain and extend a spreadsheet-like electrical distribution board circuit list editor.
|
|
|
|
The editor is used for electrical planning in execution design.
|
|
|
|
It must support circuits, device rows, project devices, drag-and-drop restructuring, stable equipment identifiers and later electrical sizing logic.
|
|
|
|
## Current Supported Architecture
|
|
|
|
- Frontend: Next.js App Router under `src/app` with reusable editor modules under `src/frontend`.
|
|
- API: Express composition starts in `src/server/index.ts`.
|
|
- Domain rules: `src/domain`.
|
|
- Persistence: SQLite/Drizzle schemas, repositories and migrations under `src/db`.
|
|
- Primary editor route:
|
|
`src/app/projects/[projectId]/circuit-lists/[circuitListId]/tree-edit/page.tsx`.
|
|
- Primary editor component: `src/frontend/components/circuit-tree-editor.tsx`.
|
|
- Grid ownership, projection, insertion and safety rules live in the pure
|
|
`src/frontend/components/circuit-grid-*.ts` modules.
|
|
- Critical multi-write commands use injected transaction repositories with real
|
|
SQLite commit/rollback tests.
|
|
- All supported runtime project-command stores, including full snapshot
|
|
restoration, share
|
|
`src/db/repositories/project-command-transaction.persistence.ts` for the
|
|
atomic domain-write, revision and history transition boundary. Its applied
|
|
forward-command variant preserves derived CircuitDeviceRow override metadata.
|
|
- Low-level `appendProjectRevision` persistence is adapter-internal and tested
|
|
directly; do not reintroduce a standalone runtime revision repository.
|
|
- Runtime domain services receive narrow reader/store dependencies explicitly;
|
|
concrete SQLite repositories are instantiated only under `src/server/composition`.
|
|
- General application repositories also require an explicit `AppDatabase`;
|
|
`src/server/composition/application-repositories.ts` owns their runtime
|
|
instances, and controllers never import the global SQLite client.
|
|
- General Circuit, CircuitDeviceRow, CircuitList and DistributionBoard
|
|
repositories expose only active reads. Runtime writes belong in typed command
|
|
repositories; direct integration fixtures belong under `tests/support`.
|
|
|
|
The supported runtime model is Circuit-First. The former Consumer UI, API,
|
|
tables and upgrade tooling are removed; do not reintroduce them.
|
|
|
|
See `docs/current-architecture.md` for the complete module and request flow.
|
|
|
|
## Critical Domain Rules
|
|
|
|
- A circuit is not the same thing as one device row.
|
|
- A circuit contains zero, one or multiple device rows.
|
|
- A single-device circuit may be displayed as one compact row.
|
|
- A multi-device circuit must be displayed with a circuit summary row and indented device rows.
|
|
- Equipment identifiers belong to circuits, not to every device row.
|
|
- Device rows inside a circuit do not have their own equipment identifiers.
|
|
- Protection and cable data belong to the circuit, not to individual devices.
|
|
- Device-level values include quantity, power per unit, simultaneity factor, cosPhi, room data, cost group and category.
|
|
- Circuit total power is the sum of all device rows in that circuit.
|
|
- Existing equipment identifiers must never be changed automatically.
|
|
- Renumbering is always an explicit user action.
|
|
|
|
## Existing Codebase Rule
|
|
|
|
There is an existing codebase.
|
|
|
|
Do not blindly continue old assumptions.
|
|
|
|
Do not blindly delete the codebase.
|
|
|
|
First audit current code against the specification.
|
|
|
|
Keep working parts if they match the target model.
|
|
|
|
Refactor or replace parts that conflict with the target model.
|
|
|
|
Before large changes, summarize:
|
|
|
|
- what is kept
|
|
- what is changed
|
|
- what is removed
|
|
- why
|
|
|
|
## Implementation Discipline
|
|
|
|
Work in phases.
|
|
|
|
Do not implement unrelated future features while working on a phase.
|
|
|
|
Before coding, briefly state:
|
|
|
|
- files to change
|
|
- data model impact
|
|
- UI impact
|
|
- risks
|
|
|
|
Prefer small, reviewable changes.
|
|
|
|
Do not rewrite the whole app unless the current architecture blocks the required domain model.
|
|
|
|
## Naming
|
|
|
|
Use English names in code.
|
|
|
|
Use clear domain names:
|
|
|
|
- `ProjectDevice`
|
|
- `DistributionBoard`
|
|
- `CircuitSection`
|
|
- `Circuit`
|
|
- `CircuitDeviceRow`
|
|
- `equipmentIdentifier`
|
|
- `displayName`
|
|
- `phaseType`
|
|
- `quantity`
|
|
- `powerPerUnit`
|
|
- `simultaneityFactor`
|
|
- `cosPhi`
|
|
- `rowTotalPower`
|
|
- `circuitTotalPower`
|
|
|
|
Avoid ambiguous names like:
|
|
|
|
- `item`
|
|
- `thing`
|
|
- `entry`
|
|
- `rowData`
|
|
|
|
Use them only for local UI variables where the context is obvious.
|
|
|
|
## Numbering Rules
|
|
|
|
Default sections:
|
|
|
|
- Lighting: prefix `-1F`
|
|
- Single-phase circuits: prefix `-2F`
|
|
- Three-phase circuits: prefix `-3F`
|
|
|
|
New circuit identifier:
|
|
|
|
- highest existing number in the section + 1
|
|
|
|
Do not fill gaps automatically.
|
|
|
|
Do not renumber after insert, delete, move, sort or drag-and-drop.
|
|
|
|
Renumber only when the user explicitly triggers "Renumber section".
|
|
|
|
## UI Rules
|
|
|
|
The circuit list table should behave like a spreadsheet.
|
|
|
|
User-facing frontend text must be German unless a domain-standard technical term
|
|
is intentionally retained.
|
|
|
|
Cells show static text by default.
|
|
|
|
Inline edit starts by:
|
|
|
|
- double click
|
|
- Enter
|
|
- typing
|
|
- F2
|
|
|
|
Keyboard behavior:
|
|
|
|
- Enter confirms
|
|
- Escape cancels
|
|
- Tab / Shift+Tab navigates editable cells
|
|
- Arrow keys navigate cells when not editing
|
|
|
|
Support Ctrl+Plus and Ctrl+Shift+Plus for insertion.
|
|
|
|
## Bootstrap / Styling Rule
|
|
|
|
Bootstrap may be used for the general application UI, such as navigation, page layout, buttons, forms, cards, alerts and modals.
|
|
|
|
Do not use Bootstrap as the core table/grid framework for the circuit list editor.
|
|
|
|
The circuit list editor must remain a custom spreadsheet-like component with controlled cell selection, inline edit mode, row grouping, drag-and-drop indicators and keyboard behavior.
|
|
|
|
Avoid permanent Bootstrap form controls inside table cells. Table cells should show static text by default and switch to inputs only while editing.
|
|
|
|
## Drag-and-Drop Rules
|
|
|
|
Dragging from the circuit identifier / circuit handle moves the whole circuit.
|
|
|
|
Dragging from the device area moves device rows.
|
|
|
|
Project devices can be dragged from a sidebar into the circuit list.
|
|
|
|
Drop onto a free placeholder creates a new circuit.
|
|
|
|
Drop onto an existing circuit adds the device to that circuit.
|
|
|
|
Moving a device recalculates affected circuit totals.
|
|
|
|
Moving rows never renumbers circuits automatically.
|
|
|
|
Show clear visual drop indicators.
|
|
|
|
Reject invalid drop targets or require confirmation.
|
|
|
|
## Sorting and Filtering
|
|
|
|
Filtering should work through column headers.
|
|
|
|
Sorting should work through column headers.
|
|
|
|
Sorting moves complete circuits as blocks.
|
|
|
|
Sorting must not split device rows away from their circuit.
|
|
|
|
Sorting does not renumber.
|
|
|
|
The user may explicitly renumber after sorting.
|
|
|
|
## Linked Project Devices
|
|
|
|
Circuit device rows may be linked to project devices.
|
|
|
|
`displayName` is copied on insert but not synchronized automatically.
|
|
|
|
When a project device changes, show affected linked rows and let the user choose which fields to sync.
|
|
|
|
Never silently overwrite local changes.
|
|
|
|
Allow disconnecting linked rows from project devices.
|
|
|
|
## Manual Rows
|
|
|
|
Manual rows are allowed and common.
|
|
|
|
Manual rows can later be saved as project devices.
|
|
|
|
After saving, the row becomes linked to the new project device.
|
|
|
|
## Undo / Redo
|
|
|
|
The editor reads undo/redo eligibility from the project-wide server history on
|
|
initial load and after every tree reload. Undo/redo therefore remains available
|
|
after a page refresh or application restart. All currently supported Circuit
|
|
and CircuitDeviceRow writes execute persistent project commands. Applying a
|
|
sorted view across multiple sections is one atomic `circuit.reorder-sections`
|
|
command and one undo step. Explicit renumbering uses the collision-safe
|
|
`circuit.renumber-section` command and is never triggered implicitly.
|
|
Immutable revision metadata is available through the paginated
|
|
`GET /api/projects/:projectId/history/revisions` endpoint; it does not expose
|
|
stored command payloads.
|
|
Named logical snapshots can be created and listed through project-scoped API
|
|
endpoints. Their schema-versioned payload contains the complete supported
|
|
project runtime state and a SHA-256, excludes global data outside the project and does
|
|
not change the project revision or undo/redo stacks. Restoring a server-stored
|
|
snapshot verifies its checksum and the current-state hash, replaces supported
|
|
project data atomically and records a new `restore` revision with a complete
|
|
inverse command. Restore can therefore be undone and redone after a restart.
|
|
Current snapshot schema version 5 additionally stores the manual quantity share
|
|
of every CircuitDeviceRow. Version 4 snapshots are upgraded with
|
|
`manualQuantity = quantity`; they already contain the complete confirmed
|
|
external-model source, import batches, room mappings and objects. Version 3
|
|
snapshots are upgraded with an empty external-model state; version 2 snapshots
|
|
are additionally upgraded with an empty external CSV configuration. Supported
|
|
baseline version 1 snapshots are additionally upgraded
|
|
with `isPublicBuilding = false`; pre-baseline snapshots remain unsupported. All
|
|
supported versions contain circuit-group identity, distribution-board components and the
|
|
separate circuit/component protection records. Portable duplicate imports
|
|
remap component ids and protection-owner references together with the existing
|
|
project graph.
|
|
Project-wide Revit CSV configuration uses
|
|
`external-csv-configuration.update`. Its complete expected/target snapshot is
|
|
persisted through the shared project-command transaction, so create, update,
|
|
delete, Undo and Redo are revision-safe. Snapshot schema 5, restore and portable
|
|
project duplication preserve the configuration; duplication remaps its internal
|
|
id and project link.
|
|
The project page exposes the Revit CSV modal. It edits the complete
|
|
transport/column/family-rule configuration through the revision-safe endpoint,
|
|
requests a stateless preview and then shows the Phase 14.2 initial-import
|
|
decisions. Preview responses include all mapped objects, while the UI renders
|
|
only the first 25. No preview or plan creates external objects, rows, revisions
|
|
or server-side drafts.
|
|
Phase 14.2 migration `0003` provides one implicit Revit CSV source per project,
|
|
immutable import batches with original bytes plus the classified cell matrix,
|
|
normalized source-room mappings and external objects unique by
|
|
`(sourceId, ifcGuid)`. Source values, planning values and overrides are separate.
|
|
The general external-model repository is read-only; runtime writes belong only
|
|
to typed command adapters. Snapshot/restore and portable project transfer schema version 5
|
|
capture the complete external state and remap every internal UUID and link while
|
|
preserving IFCGUIDs, source values, original bytes and the classified matrix.
|
|
Import batches additionally store the monotonic project CSV configuration
|
|
version introduced by additive migration `0004`; it is distinct from the CSV
|
|
configuration JSON schema version.
|
|
Phase 14.3 migration `0005` adds `CircuitDeviceRow.manualQuantity`, backfills
|
|
existing rows from `quantity` and keeps `quantity` as the materialized total.
|
|
Normal manual row inserts and quantity edits update both values together. Future
|
|
external-object assignment commands must set the total to `manualQuantity` plus
|
|
the sum of linked objects' effective quantities in the same transaction.
|
|
Confirmed initial state is written only through
|
|
`external-import.apply-initial`. The command rechecks configuration version,
|
|
original-byte SHA-256, parsed matrix, complete IFCGUID/source values, explicit
|
|
planning overrides and internal project links in the shared transaction. It
|
|
never creates or links a CircuitDeviceRow. Its exact inverse removes the whole
|
|
unchanged external state, and Redo restores the same UUIDs and bytes.
|
|
`POST /api/projects/:projectId/external-csv/initial-import/plan` is a stateless
|
|
read path for the first wizard stage. It rejects projects with an existing
|
|
external source and returns source-room groups, exact room-number suggestions,
|
|
exact family/type groups, projected object values, issue counts and the current
|
|
floor/room/board/ProjectDevice catalogs. It creates no draft, revision or
|
|
domain row. The wide modal renders these groups and catalogs as explicit
|
|
decisions and identifies exact, ambiguous and new room matches. Missing rooms
|
|
and ProjectDevices are created through the reused project forms with mapped
|
|
Revit values as visible defaults. Each catalog creation remains its own project
|
|
command; the wizard adds and selects the result without discarding its plan.
|
|
The dedicated
|
|
`POST /api/projects/:projectId/external-csv/initial-import/apply` endpoint
|
|
retransmits and replans the file against the expected hash, configuration
|
|
version and project revision. It requires one explicit decision per source-room
|
|
and exact family/type group, blocks unclassified families, creates all stable
|
|
external UUIDs server-side and invokes `external-import.apply-initial`.
|
|
Room/default-board and optional ProjectDevice links are supported; CSV circuit
|
|
values remain source-only and every `circuitDeviceRowId` remains null. The UI
|
|
blocks unclassified families, requires a final confirmation and applies the
|
|
whole import as one persistent Undo/Redo step.
|
|
The central revision boundary creates an automatic logical snapshot after each
|
|
25 new revisions and retains only the newest 12 automatic snapshots per
|
|
project. Named snapshots are never removed by this retention policy.
|
|
The project page exposes persistent project-wide Undo/Redo in the header of an
|
|
initially collapsed German snapshot/timeline UI, with explicit restore
|
|
confirmation and cursor-based loading of older revision metadata.
|
|
Insertions and generated move targets use client-generated stable UUIDs, and
|
|
undo restores the same ids from complete server snapshots. The tree response
|
|
supplies the optimistic `currentRevision`; obsolete direct field PATCH,
|
|
structure POST, move, reorder, renumber, identifier-restore, Circuit and
|
|
CircuitDeviceRow DELETE routes are removed.
|
|
CircuitDeviceRow moves between existing circuits and moves that create one new
|
|
placeholder target circuit are persisted. The latter stores the complete empty
|
|
target snapshot so undo can restore the rows and remove only the unchanged
|
|
generated circuit. Complete
|
|
in-section Circuit reorders are persisted separately and change sort positions
|
|
without changing equipment identifiers. Explicit complete-section renumbering
|
|
is persisted through a separate collision-safe command and is never triggered
|
|
by sorting or moving. Project-device synchronization, disconnect and reconnect
|
|
are persisted as one atomic multi-row command with complete expected/target row
|
|
snapshots, including link and override metadata. Canonical ProjectDevice field
|
|
updates are also persisted and never synchronize linked rows implicitly.
|
|
ProjectDevice insertion/deletion preserves stable device ids. Deletion captures
|
|
complete disconnected snapshots of linked rows so undo can restore only rows
|
|
that have remained unchanged. ProjectDevice create, update, delete and
|
|
global-to-project copy API/UI paths use these persistent commands and track the
|
|
returned project revision. ProjectDevice synchronization/disconnect API and UI
|
|
paths do the same; their undo action uses the project-wide history endpoint.
|
|
Project settings use the persistent `project.update-settings` command. Project
|
|
metadata, the public-building classification, both voltage defaults and the
|
|
enabled distribution-board supply types change in one revision and Undo/Redo
|
|
restores them together; the project PUT route requires `expectedRevision`.
|
|
The public-building flag is the future sizing input for requiring halogen-free
|
|
cables and lines. The system catalog is `AV`, `SV`, `EV`,
|
|
`USV`, `MSR`, `SiBe`; at least one must be enabled and a type used by a board
|
|
cannot be disabled.
|
|
Distribution-board setup uses `distribution-board.insert` schema version 1
|
|
with a complete stable snapshot of the board, circuit list, three default
|
|
groups, main switch `-Q0` and surge protective device `-FA`. Its
|
|
inverse removes only the same unchanged and still-empty structure; the POST
|
|
route requires `expectedRevision` and returns the updated history state.
|
|
Complete populated distribution-board copying and deletion use
|
|
`distribution-board.insert-subtree` and `distribution-board.delete-subtree`.
|
|
Their exact snapshots include the board, circuit list, groups, circuits,
|
|
device rows, components and all one-to-one protection data. Copy remaps all
|
|
owning ids but preserves project-device and room links. Both operations are
|
|
atomic persistent commands with restart-safe Undo/Redo; deletion requires an
|
|
explicit UI warning.
|
|
Mutable group-protection and auxiliary distribution-board components use
|
|
`distribution-board-component.insert` and
|
|
`distribution-board-component.delete`; edits and footer reordering use
|
|
`distribution-board-component.update`. Their complete expected/target
|
|
snapshots include the optional one-to-one protection-device state and reject
|
|
stale data. Updates preserve id, ownership, role and placement. Fixed
|
|
main-switch and surge-protection header roles are excluded from these general
|
|
component commands.
|
|
Empty circuit-group creation, display-name updates and deletion use
|
|
`circuit-group.insert`, `circuit-group.update` and `circuit-group.delete`.
|
|
Their snapshots keep category, positive group number and derived prefix
|
|
consistent. General deletion rejects groups containing circuits or group
|
|
components; populated deletion remains a separate confirmed command.
|
|
`circuit-group.reorder` requires a complete expected/target sort assignment for
|
|
every group in one circuit list. It changes only sort positions and never
|
|
renumbers groups, prefixes or circuits.
|
|
Explicit group-number changes use `circuit-group.renumber`. The command carries
|
|
the complete expected/target group, circuit-BMK and optional group-component
|
|
BMK plan, applies swaps through collision-safe temporary values and preserves
|
|
circuit suffixes. Undo/Redo uses the exact inverse plan.
|
|
Cross-group circuit moves use `circuit.move-group` and are limited to distinct
|
|
groups of the same category. The stored target BMK is highest target suffix
|
|
plus one at planning time and is never recalculated for Redo. Only circuit
|
|
group, BMK and sort order change; device rows and circuit protection retain the
|
|
stable circuit id.
|
|
Confirmed populated-group deletion uses
|
|
`circuit-group.delete-subtree`/`circuit-group.restore-subtree`. The exact
|
|
snapshot contains the group, optional component protections, complete circuits,
|
|
circuit protections and all device-row link/override metadata. Delete
|
|
re-captures and compares the subtree before cascading; restore preserves every
|
|
UUID in foreign-key-safe order.
|
|
The circuit-tree read model exposes fixed `headerComponents`, group-owned
|
|
`components`, `footerComponents`, optional group category/number and optional
|
|
one-to-one protection DTOs for circuits and group components. These are
|
|
the only supported circuit-protection source; no flat compatibility fields remain.
|
|
Distribution-board floor assignment and a project-enabled supply type use
|
|
`distribution-board.update`; both values are snapshot/export fields and one
|
|
persistent undo step.
|
|
Floor and room setup uses persistent insert, update and delete commands with
|
|
complete stable snapshots. Their inverses remove or restore only unchanged records and
|
|
reject floors with assigned rooms/distribution boards or rooms referenced by
|
|
device rows. All write routes require `expectedRevision` and return the updated
|
|
history state.
|
|
|
|
Required operations:
|
|
|
|
- insert circuit
|
|
- insert device
|
|
- delete circuit
|
|
- delete device
|
|
- move circuit
|
|
- move device
|
|
- multi-row move
|
|
- renumber section
|
|
- edit cell value
|
|
- edit equipment identifier
|
|
- synchronization changes
|
|
|
|
|
|
## Revit / CSV External Model Work
|
|
|
|
When explicitly working on Phase 14, use
|
|
`docs/spec/revit-csv-integration-requirements.md` as the detailed source of
|
|
truth together with the current architecture documents.
|
|
|
|
Critical rules:
|
|
|
|
- Revit integration is optional. Do not make imported external data mandatory
|
|
for projects, rooms, project devices, circuits or device rows.
|
|
- Parse imports into staging first. Never write CSV rows directly into circuits
|
|
or device rows.
|
|
- Keep external object identity separate from internal UUIDs and circuit BMKs.
|
|
`IfcGUID` identifies the external Revit object and must never replace an
|
|
internal UUID or `equipmentIdentifier`.
|
|
- One imported Revit object may exist without a `CircuitDeviceRow`.
|
|
Import, room assignment, distribution-board assignment, classification and
|
|
ProjectDevice linking do not create a row.
|
|
- Create or change a `CircuitDeviceRow` only after an explicit user action in
|
|
the circuit-list editor.
|
|
- Several external objects may link to one `CircuitDeviceRow`, while every
|
|
external object remains individually traceable for follow-up imports and
|
|
object-specific export.
|
|
- Multi-socket Revit objects are indivisible. Their effective quantity may be
|
|
greater than one, but one external object must never be split across circuits.
|
|
- Existing ProjectDevices are canonical project templates and must not be
|
|
overwritten from Revit values. When creating a new ProjectDevice, mapped
|
|
Revit values may prefill the creation form.
|
|
- Store imported source values separately from local planning values and local
|
|
overrides. Imports never silently overwrite local values.
|
|
- Repeated imports match deterministically by project/source and `IfcGUID`.
|
|
New, changed, missing and conflicting objects require preview and explicit
|
|
user decisions.
|
|
- The first implementation assumes one complete Revit model export per project.
|
|
Do not add visible multi-source, linked-model or partial-import management.
|
|
- CSV configuration is project-scoped. Preserve title, header, blank, subtotal
|
|
and unknown rows and columns for the return export.
|
|
- Treat rows without `IfcGUID` as passthrough when they contain no object data.
|
|
Do not report Revit subtotal rows as missing-identity objects.
|
|
- Apply each confirmed import diff through a typed project command with
|
|
`expectedRevision`, complete inverse data and the shared project command
|
|
transaction boundary.
|
|
- External-model state must be added to logical project snapshots and portable
|
|
project transfer when it becomes part of the supported runtime.
|
|
- Keep CSV parsing/serialization in a transport adapter. Domain services must
|
|
not depend on CSV syntax, React, `better-sqlite3` or concrete repositories.
|
|
- Do not implement automatic circuit planning, Dynamo/API exchange,
|
|
PostgreSQL, background jobs or permissions as part of the initial CSV phase.
|
|
|
|
Before implementation, audit the current ProjectDevice, CircuitDeviceRow,
|
|
command, snapshot, transfer and editor drag-and-drop paths. Propose concrete
|
|
domain objects and commands before adding migrations.
|
|
|
|
## Future Sizing
|
|
|
|
Do not implement full cable/protection sizing unless explicitly requested.
|
|
|
|
Keep the structure ready for it.
|
|
|
|
Future sizing will need:
|
|
|
|
- circuit total power
|
|
- phase type
|
|
- voltage
|
|
- cosPhi
|
|
- cable length
|
|
- cable type
|
|
- cable cross-section
|
|
- protection rated current
|
|
- control requirement such as DALI
|
|
|
|
Users must be able to override sizing suggestions.
|
|
|
|
## Persistence and Migration Rules
|
|
|
|
- SQLite is the currently supported database.
|
|
- Migration `0000` is the clean release baseline for empty databases.
|
|
- Pre-baseline development databases, snapshots and stored commands are not
|
|
supported.
|
|
- After the first release, never edit an already applied migration.
|
|
- Back up an existing database before applying a new migration.
|
|
- Inspect generated SQL; it must contain only the intended schema change.
|
|
- Keep database backups separate from logical project snapshots.
|
|
- Do not import the global SQLite singleton into domain services.
|
|
- Keep synchronous SQLite transaction behavior inside persistence adapters.
|
|
- Preserve stable UUIDs and explicit transaction boundaries for a later
|
|
PostgreSQL adapter.
|
|
|
|
## Current Deferred Work
|
|
|
|
- Revit/CSV/IFCGUID round-trip, except when Phase 14 is explicitly requested and
|
|
`docs/spec/revit-csv-integration-requirements.md` is being followed
|
|
- full electrical sizing
|
|
- multi-user/PostgreSQL operation
|
|
- supported production deployment
|
|
|
|
Do not implement these while working on an unrelated phase.
|
|
|
|
## Documentation and Verification
|
|
|
|
- `README.md` is the setup entry point.
|
|
- `docs/README.md` is the documentation map.
|
|
- `docs/current-architecture.md` describes current code paths.
|
|
- `docs/spec/` contains requirements and roadmap, not proof of implementation.
|
|
- `docs/archive/` is historical and must not drive current implementation.
|
|
|
|
For a normal code change run the relevant focused tests plus:
|
|
|
|
- `npm test`
|
|
- `npm run build:api`
|
|
- `npm run build:web`
|
|
- `npm run typecheck:scripts`
|
|
- `npx tsc --noEmit -p tsconfig.next.json`
|
|
|
|
Use a concise imperative commit message for each completed, verified work package.
|
|
|
|
## Response Style for Codex
|
|
|
|
Be concise.
|
|
|
|
Do not restate the whole specification.
|
|
|
|
Reference the relevant file and section.
|
|
|
|
When uncertain, choose the simplest implementation that preserves the domain model.
|
|
|
|
Do not add libraries unless there is a clear reason.
|
|
|
|
Do not introduce global state management unless needed.
|