Problem
The current 3U flip feature stores orientation in rack_modules.orientation as checked text: normal or rot180. The semantic model is correct, but text is not the right physical representation for a small finite state. It consumes more storage and wire payload than than necessary and encourages database strings to leak into application logic.
Decision
Store orientation as smallint:
| Database value |
Application meaning |
0 |
normal |
1 |
rot180 |
2+ |
Reserved for reviewed future 1U/orientation states |
Keep RackModuleOrientation semantic names in TypeScript. Translate numbers to names only in the Supabase read/write boundary so UI and domain code remain readable.
Migration outline
- Read
patterns/BACKEND_METHODS.md schema-change preflight and inspect the live column, constraint, policies, table size, and dependent views/functions.
- Drop the text default and
rack\_modules\_orientation\_check constraint.
- Convert the column with an explicit
USING CASE mapping: normal -> 0, rot180 -> 1; reject unexpected values rather than silently coercing them.
- Set
smallint NOT NULL DEFAULT 0 and add a numeric check constraint covering only currently supported values (0, 1).
- Regenerate
src/backend/database.types.ts.
- Update Supabase read/insert/targeted-update mappings to translate numeric storage to the semantic TypeScript union. Existing layout batch updates must continue to omit orientation.
- Add compatibility tests for
0, 1, null/malformed defensive reads, new-placement defaults, targeted writes, and preservation during layout operations.
- Run targeted specs,
pnpm lint, docs check, and pnpm updateBackendTypes after an approved apply.
Risks
The type conversion may rewrite rack_modules and briefly lock the table. Schedule the remote apply deliberately after checking table size and active traffic.
Acceptance criteria
- Existing
normal and rot180 rows become 0 and 1 without changing placement ids, rack ownership, timestamps, layout, or visible orientation.
- New placements default to
0.
- The application continues to expose only semantic orientation names outside the backend boundary.
- Flip, undo, public rendering, patch rendering, duplication, move/remix, and rollback behavior remain unchanged.
- Old generic rack-module batch writes cannot overwrite orientation.
- Generated types, focused tests, lint, docs check, and post-apply advisors pass.
Documentation impact
Migrated from local documentation.
Source: internaldocs/workflow/plans/rack-module-orientation-smallint-storage-migration.md
Migration status: migrated from local documentation
Preserved source plan (restored)
The earlier migration body condensed this source. The complete local source is restored verbatim below.
Rack module orientation — smallint storage migration
Status
Open. Documentation and design decision recorded 2026-07-19. Schema application,
type generation, and backend changes require explicit product-owner approval and the
standard schema-change preflight. No RLS or policy change is expected.
Problem
The completed 3U flip feature stores placement orientation in
rack_modules.orientation as checked text: normal or rot180. The semantic model is
correct, but text is not the right physical representation for a small finite state.
It consumes more storage and wire payload than necessary and encourages database
strings to leak into application logic.
Decision
Store orientation as smallint:
| Database value |
Application meaning |
0 |
normal |
1 |
rot180 |
2+ |
Reserved for reviewed future 1U/orientation states |
Keep RackModuleOrientation semantic names in TypeScript. Translate numbers to names
only in the Supabase read/write boundary so UI and domain code remain readable.
Do not use a boolean: it is compact but cannot represent the already anticipated 1U
orientation variants. Do not use a PostgreSQL enum: it is less flexible to extend and
still couples schema migrations to semantic labels.
Migration outline
- Read
patterns/BACKEND_METHODS.md schema-change preflight and inspect the live
column, constraint, policies, table size, and dependent views/functions.
- Drop the text default and
rack_modules_orientation_check constraint.
- Convert the column with an explicit
USING CASE mapping:
normal -> 0, rot180 -> 1; reject unexpected values rather than silently
coercing them.
- Set
smallint NOT NULL DEFAULT 0 and add a numeric check constraint covering only
currently supported values (0, 1).
- Regenerate
src/backend/database.types.ts.
- Update Supabase read/insert/targeted-update mappings to translate numeric storage
to the semantic TypeScript union. Existing layout batch updates must continue to
omit orientation.
- Add compatibility tests for
0, 1, null/malformed defensive reads, new-placement
defaults, targeted writes, and preservation during layout operations.
- Run targeted specs,
pnpm lint, docs check, git diff --check, then Supabase
security/performance advisors after an approved apply.
The type conversion may rewrite rack_modules and briefly lock the table. Schedule the
remote apply deliberately after checking table size and active traffic. ALTER COLUMN TYPE ... USING must not use a row-by-row application backfill and must not change RLS,
policies, grants, or placement ownership semantics.
Acceptance criteria
- Existing
normal and rot180 rows become 0 and 1 without changing placement
ids, rack ownership, timestamps, layout, or visible orientation.
- New placements default to
0.
- The application continues to expose only semantic orientation names outside the
backend boundary.
- Flip, undo, public rendering, patch rendering, duplication, move/remix, and rollback
behavior remain unchanged.
- Old generic rack-module batch writes cannot overwrite orientation.
- Generated types, focused tests, lint, docs, diff check, and post-apply advisors pass.
Decision log
- 2026-07-19 — Product owner rejected text as the physical storage representation.
Chose smallint over boolean to retain a compact extension path for future 1U
orientation states, while keeping semantic string names inside the application.
Source and migration metadata
Source: internaldocs/workflow/plans/rack-module-orientation-smallint-storage-migration.md
Migration status: migrated from local documentation
Problem
The current 3U flip feature stores orientation in
rack_modules.orientationas checked text:normalorrot180. The semantic model is correct, but text is not the right physical representation for a small finite state. It consumes more storage and wire payload than than necessary and encourages database strings to leak into application logic.Decision
Store orientation as
smallint:0normal1rot1802+Keep
RackModuleOrientationsemantic names in TypeScript. Translate numbers to names only in the Supabase read/write boundary so UI and domain code remain readable.Migration outline
patterns/BACKEND_METHODS.mdschema-change preflight and inspect the live column, constraint, policies, table size, and dependent views/functions.rack\_modules\_orientation\_checkconstraint.USING CASEmapping:normal -> 0,rot180 -> 1; reject unexpected values rather than silently coercing them.smallint NOT NULL DEFAULT 0and add a numeric check constraint covering only currently supported values (0,1).src/backend/database.types.ts.0,1, null/malformed defensive reads, new-placement defaults, targeted writes, and preservation during layout operations.pnpm lint, docs check, andpnpm updateBackendTypesafter an approved apply.Risks
The type conversion may rewrite
rack_modulesand briefly lock the table. Schedule the remote apply deliberately after checking table size and active traffic.Acceptance criteria
normalandrot180rows become0and1without changing placement ids, rack ownership, timestamps, layout, or visible orientation.0.Documentation impact
Migrated from local documentation.
Source: internaldocs/workflow/plans/rack-module-orientation-smallint-storage-migration.md
Migration status: migrated from local documentation
Preserved source plan (restored)
The earlier migration body condensed this source. The complete local source is restored verbatim below.
Rack module orientation — smallint storage migration
Status
Open. Documentation and design decision recorded 2026-07-19. Schema application,
type generation, and backend changes require explicit product-owner approval and the
standard schema-change preflight. No RLS or policy change is expected.
Problem
The completed 3U flip feature stores placement orientation in
rack_modules.orientationas checked text:normalorrot180. The semantic model iscorrect, but text is not the right physical representation for a small finite state.
It consumes more storage and wire payload than necessary and encourages database
strings to leak into application logic.
Decision
Store orientation as
smallint:0normal1rot1802+Keep
RackModuleOrientationsemantic names in TypeScript. Translate numbers to namesonly in the Supabase read/write boundary so UI and domain code remain readable.
Do not use a boolean: it is compact but cannot represent the already anticipated 1U
orientation variants. Do not use a PostgreSQL enum: it is less flexible to extend and
still couples schema migrations to semantic labels.
Migration outline
patterns/BACKEND_METHODS.mdschema-change preflight and inspect the livecolumn, constraint, policies, table size, and dependent views/functions.
rack_modules_orientation_checkconstraint.USING CASEmapping:normal -> 0,rot180 -> 1; reject unexpected values rather than silentlycoercing them.
smallint NOT NULL DEFAULT 0and add a numeric check constraint covering onlycurrently supported values (
0,1).src/backend/database.types.ts.to the semantic TypeScript union. Existing layout batch updates must continue to
omit orientation.
0,1, null/malformed defensive reads, new-placementdefaults, targeted writes, and preservation during layout operations.
pnpm lint, docs check,git diff --check, then Supabasesecurity/performance advisors after an approved apply.
The type conversion may rewrite
rack_modulesand briefly lock the table. Schedule theremote apply deliberately after checking table size and active traffic.
ALTER COLUMN TYPE ... USINGmust not use a row-by-row application backfill and must not change RLS,policies, grants, or placement ownership semantics.
Acceptance criteria
normalandrot180rows become0and1without changing placementids, rack ownership, timestamps, layout, or visible orientation.
0.backend boundary.
behavior remain unchanged.
Decision log
Chose
smallintover boolean to retain a compact extension path for future 1Uorientation states, while keeping semantic string names inside the application.
Source and migration metadata
Source: internaldocs/workflow/plans/rack-module-orientation-smallint-storage-migration.md
Migration status: migrated from local documentation