Compare commits
2 Commits
1d89a4918e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d2600f1279 | |||
| 472b3e10d9 |
@@ -37,6 +37,8 @@ Read additional contracts by task type:
|
||||
`local-first-recovery`
|
||||
- Tables, bulk actions, filters, pagination:
|
||||
`table-management`, `controls-selection`
|
||||
- Visual style for server-rendered web apps:
|
||||
`web-visual-baseline`, `table-management`, `controls-selection`
|
||||
- Forms, validation, modals:
|
||||
`forms-validation`, `modal-workflows`
|
||||
- Import/export, CSV, upload batching:
|
||||
|
||||
@@ -3,20 +3,39 @@
|
||||
## Rule
|
||||
|
||||
Before starting any work on a task, check whether the remote repository has commits that are not yet present locally.
|
||||
This rule assumes the repository is hosted in Gitea.
|
||||
Use neutral `git` commands for sync checks and branch management, and use Gitea terminology for server-side review flow (`pull request`, not `merge request`).
|
||||
|
||||
## Required Steps
|
||||
|
||||
1. Run `git fetch` to update remote-tracking refs without merging.
|
||||
1. Run `git fetch origin` to update remote-tracking refs from the Gitea remote without merging.
|
||||
2. Check for upstream commits: `git log HEAD..@{u} --oneline`.
|
||||
3. If the output is non-empty (there are new remote commits):
|
||||
- **Stop immediately. Do not make any changes.**
|
||||
- Inform the user that the remote has new commits and ask how to proceed (e.g., pull, rebase, or ignore).
|
||||
4. If the output is empty, proceed with the task normally.
|
||||
|
||||
## Gitea Workflow Notes
|
||||
|
||||
- Verify the remote when needed: `git remote -v`
|
||||
- Create a task branch before changes: `git checkout -b <task-branch>`
|
||||
- Push the branch to Gitea and set upstream: `git push -u origin <task-branch>`
|
||||
- Open the review in Gitea as a pull request against the target branch.
|
||||
- If the `tea` CLI is configured for the environment, it may be used for Gitea pull request actions such as:
|
||||
- `tea pr list`
|
||||
- `tea pr create`
|
||||
- `tea pr checkout <number>`
|
||||
|
||||
## Forbidden Assumptions
|
||||
|
||||
- Do not assume GitHub-specific tooling such as `gh`.
|
||||
- Do not use GitLab terminology such as `merge request` unless a project explicitly defines that workflow separately.
|
||||
- Do not replace the required sync check with web UI inspection in Gitea; the local `git fetch origin` and `git log HEAD..@{u} --oneline` check remains mandatory.
|
||||
|
||||
## Rationale
|
||||
|
||||
Working on an outdated local state risks merge conflicts, duplicate work, and overwriting changes made by other contributors. Checking remote state first keeps the working tree aligned and prevents avoidable conflicts.
|
||||
Working on an outdated local state risks merge conflicts, duplicate work, and overwriting changes made by other contributors. Checking remote state first keeps the working tree aligned and prevents avoidable conflicts. Using Gitea-specific review terminology and examples also avoids workflow confusion in repositories that are not hosted on GitHub or GitLab.
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Offline environments where `git fetch` is not possible: notify the user that the check could not be performed before proceeding.
|
||||
- Offline environments where `git fetch origin` is not possible: notify the user that the check could not be performed before proceeding.
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
Version: 1.1
|
||||
|
||||
## Source Text and Comments
|
||||
|
||||
- Use plain ASCII in source code and comments by default.
|
||||
- Do not use em dash, emoji, or other decorative Unicode markers in code, comments, log messages, or user-facing fallback strings unless a feature explicitly requires non-ASCII text.
|
||||
- Do not leave AI-style markers in the codebase: ornamental phrasing, assistant-like filler, synthetic enthusiasm, or comments that read like generated prose instead of technical documentation.
|
||||
- Comments must be short, concrete, and technical. Explain intent, invariants, or non-obvious constraints; do not write marketing-style or conversational commentary.
|
||||
|
||||
## Logging
|
||||
|
||||
See `kit/patterns/go-logging/contract.md` for full rules.
|
||||
@@ -18,7 +25,7 @@ if err := db.Save(&record).Error; err != nil {
|
||||
return fmt.Errorf("save component %s: %w", record.ID, err)
|
||||
}
|
||||
|
||||
// WRONG — loses context
|
||||
// WRONG: loses context
|
||||
return err
|
||||
```
|
||||
|
||||
@@ -35,9 +42,9 @@ return err
|
||||
Handlers are thin. Business logic belongs in a service layer.
|
||||
|
||||
```
|
||||
Handler → validates input, calls service, writes response
|
||||
Service → business logic, calls repository
|
||||
Repository → SQL queries only, returns domain types
|
||||
Handler -> validates input, calls service, writes response
|
||||
Service -> business logic, calls repository
|
||||
Repository -> SQL queries only, returns domain types
|
||||
```
|
||||
|
||||
- Handlers must not contain SQL queries.
|
||||
@@ -48,7 +55,7 @@ Repository → SQL queries only, returns domain types
|
||||
|
||||
```
|
||||
1. Parse flags / load config
|
||||
2. Connect to DB — fail fast if unavailable (see go-database contract)
|
||||
2. Connect to DB; fail fast if unavailable (see go-database contract)
|
||||
3. Run migrations
|
||||
4. Initialize services and background workers
|
||||
5. Register routes
|
||||
@@ -69,14 +76,14 @@ Never reverse steps 2 and 5. Never start serving before migrations complete.
|
||||
## Template / UI Rendering
|
||||
|
||||
- Server-rendered HTML via Go templates is the default.
|
||||
- htmx for partial updates — no full SPA framework unless explicitly decided.
|
||||
- htmx for partial updates; no full SPA framework unless explicitly decided.
|
||||
- Template errors must return `500` and log the error server-side.
|
||||
- Never expose raw Go error messages to the end user in rendered HTML.
|
||||
|
||||
## Business Logic Placement
|
||||
|
||||
- Threshold computation, status derivation, and scoring live on the server.
|
||||
- The UI only reflects what the server returns — it does not recompute status client-side.
|
||||
- The UI only reflects what the server returns; it does not recompute status client-side.
|
||||
- Example: "critical / warning / ok" badge color is determined by the handler, not by JS.
|
||||
|
||||
## Dependency Rules
|
||||
|
||||
@@ -16,29 +16,29 @@ Every project bible must have these files:
|
||||
|
||||
```
|
||||
bible-local/
|
||||
README.md — index: what files exist and what each covers
|
||||
README.md - index: what files exist and what each covers
|
||||
architecture/
|
||||
system-overview.md — what the product does, active scope, non-goals
|
||||
data-model.md — domain entities, DB tables, naming conventions
|
||||
api-surface.md — all HTTP endpoints with methods and response shape
|
||||
runtime-flows.md — key mutation flows, invariants, critical rules
|
||||
system-overview.md - what the product does, active scope, non-goals
|
||||
data-model.md - domain entities, DB tables, naming conventions
|
||||
api-surface.md - all HTTP endpoints with methods and response shape
|
||||
runtime-flows.md - key mutation flows, invariants, critical rules
|
||||
decisions/
|
||||
README.md — ADL format explanation
|
||||
YYYY-MM-DD-topic.md — one file per architectural decision
|
||||
README.md - ADL format explanation
|
||||
YYYY-MM-DD-topic.md - one file per architectural decision
|
||||
```
|
||||
|
||||
Optional (add when relevant):
|
||||
```
|
||||
architecture/
|
||||
ui-information-architecture.md — page structure, navigation, UI invariants
|
||||
ui-information-architecture.md - page structure, navigation, UI invariants
|
||||
docs/
|
||||
INTEGRATION_GUIDE.md — external system integration (formats, protocols)
|
||||
INTEGRATION_GUIDE.md - external system integration (formats, protocols)
|
||||
```
|
||||
|
||||
## system-overview.md Rules
|
||||
|
||||
- List what is **in scope** and what is **explicitly out of scope**.
|
||||
- Out of scope section prevents scope creep — update it when you reject a feature.
|
||||
- Out of scope section prevents scope creep; update it when you reject a feature.
|
||||
- Include tech stack and local run command.
|
||||
|
||||
## data-model.md Rules
|
||||
@@ -63,7 +63,7 @@ This is the most important file. Document flows that are **easy to break**:
|
||||
- Event/time source priority rules
|
||||
- Deduplication logic
|
||||
- Cross-entity side effects (e.g. removing a component affects asset status)
|
||||
- Anything that caused a bug or regression — add a "DO NOT reintroduce" note
|
||||
- Anything that caused a bug or regression: add a "DO NOT reintroduce" note
|
||||
|
||||
Format each flow as a numbered list of steps, not prose.
|
||||
|
||||
@@ -94,19 +94,20 @@ What this means going forward. What is now forbidden or required.
|
||||
```
|
||||
|
||||
- One decision per file, named `YYYY-MM-DD-short-topic.md`.
|
||||
- When a decision is superseded, add `superseded by` to the old file's status — do not delete it.
|
||||
- When a decision is superseded, add `superseded by` to the old file's status; do not delete it.
|
||||
- Record the decision **in the same commit** as the code that implements it.
|
||||
|
||||
## What NOT to Put in bible-local/
|
||||
|
||||
- Generic rules (CSV format, logging, pagination) → these are in `bible/rules/patterns/`
|
||||
- Work-in-progress notes, TODO lists → use issues or a separate `docs/` folder
|
||||
- Generic rules (CSV format, logging, pagination) -> these are in `bible/rules/patterns/`
|
||||
- Work-in-progress notes, TODO lists -> use issues or a separate `docs/` folder
|
||||
- Duplicate of what is already in code (don't restate what the code clearly shows)
|
||||
- Speculative future architecture — document what exists, not what might exist
|
||||
- Speculative future architecture: document what exists, not what might exist
|
||||
|
||||
## Keeping the Bible Current
|
||||
|
||||
- Update `bible-local/` in the **same commit** as the code change it describes.
|
||||
- If you change a flow, update `runtime-flows.md` in the same PR.
|
||||
- If a section becomes outdated, fix or delete it — stale docs are worse than no docs.
|
||||
- If a section becomes outdated, fix or delete it; stale docs are worse than no docs.
|
||||
- Bible files are in **English only**.
|
||||
- Do not use em dash in Bible files; prefer ASCII punctuation such as `-`, `:`, or `;` depending on the sentence.
|
||||
|
||||
302
rules/patterns/web-visual-baseline/contract.md
Normal file
302
rules/patterns/web-visual-baseline/contract.md
Normal file
@@ -0,0 +1,302 @@
|
||||
# Contract: Web Visual Baseline
|
||||
|
||||
Version: 1.0
|
||||
|
||||
## Scope
|
||||
|
||||
Defines the default visual baseline for future web applications in this ecosystem.
|
||||
|
||||
The canonical reference is the UI style from:
|
||||
|
||||
- `/Users/mchusavitin/Documents/git/chart/web/static/view.css`
|
||||
- `/Users/mchusavitin/Documents/git/chart/web/templates/view.html`
|
||||
- `/Users/mchusavitin/Documents/git/chart/web/templates/upload.html`
|
||||
|
||||
When a project does not already have an established design system, use this baseline by default.
|
||||
|
||||
## Core Direction
|
||||
|
||||
- Prefer a clean, data-first interface over decorative marketing UI.
|
||||
- Default to server-rendered HTML with simple CSS.
|
||||
- Optimize for scanability, density, and operational clarity.
|
||||
- Use restrained visual hierarchy, not novelty effects.
|
||||
- Reuse the baseline directly when possible; copying the canonical CSS and adapting tokens is allowed.
|
||||
|
||||
## Canonical Visual Language
|
||||
|
||||
- Dark application header on top.
|
||||
- White page background and white content surfaces.
|
||||
- Light secondary surfaces for headers and table heads.
|
||||
- Thin gray borders with a subtle shadow.
|
||||
- Small radii (`4px`).
|
||||
- Dense but readable typography (`14px/1.5` baseline).
|
||||
- Blue accent in the `#2185d0` family for primary actions and active accents.
|
||||
- Tables and key-value layouts as the primary presentation pattern.
|
||||
- Status communicated with both text and color.
|
||||
|
||||
## Typography
|
||||
|
||||
- Use `Lato, "Helvetica Neue", Arial, Helvetica, sans-serif` unless a project has an approved alternative.
|
||||
- Page titles are compact and strong, not oversized hero typography.
|
||||
- Section titles should be clear and structural.
|
||||
- Avoid display fonts, novelty fonts, and oversized marketing headings in application UI.
|
||||
|
||||
## Layout Primitives
|
||||
|
||||
- `page-header`: dark global header with page title and compact actions.
|
||||
- `page-main`: centered content area with generous outer margin and bounded max width.
|
||||
- `panel`: white surface with border, light shadow, and simple heading strip.
|
||||
- `section-card`: heading followed by table/content block.
|
||||
- `table-wrap`: horizontal overflow container for dense data tables.
|
||||
|
||||
## Preferred Components
|
||||
|
||||
- Key-value tables for singleton object/detail views.
|
||||
- Dense data tables for repeated records.
|
||||
- Compact upload/open panels when local file input is needed.
|
||||
- Quiet header actions for secondary navigation.
|
||||
- Clear primary buttons for the main action on a screen.
|
||||
- Simple alert/error boxes with border + tinted background.
|
||||
|
||||
## Status Rules
|
||||
|
||||
- `OK`: green
|
||||
- `Warning`: amber
|
||||
- `Critical`: red
|
||||
- `Unknown`: gray
|
||||
- `Empty`: light gray
|
||||
|
||||
Status must not rely on color alone.
|
||||
Show text or another explicit indicator together with the color treatment.
|
||||
|
||||
## Responsive Rules
|
||||
|
||||
- Keep desktop density high.
|
||||
- Collapse grids to one column on small screens.
|
||||
- Preserve table readability with horizontal scrolling instead of destructive cardification by default.
|
||||
- Header actions may wrap or stack on mobile, but should remain compact.
|
||||
|
||||
## Forbidden Drift
|
||||
|
||||
- Do not default to glassmorphism, blurred shells, floating neon gradients, or soft-dribbble styling.
|
||||
- Do not replace dense tables with oversized card grids when the data is inherently tabular.
|
||||
- Do not introduce arbitrary color coding for non-status fields.
|
||||
- Do not use oversized border radii, heavy shadows, or large empty spacing as the default application style.
|
||||
- Do not import a SPA/dashboard aesthetic unless the product explicitly requires it.
|
||||
|
||||
## Relationship To Other UI Contracts
|
||||
|
||||
- Use this contract as the visual baseline.
|
||||
- Use `table-management` for shared table geometry and interaction seams.
|
||||
- Use `controls-selection` for button hierarchy, filters, and bulk selection semantics.
|
||||
- Pattern-specific contracts may override details only when they document the reason.
|
||||
|
||||
## Copyable Starter CSS
|
||||
|
||||
Use this as the default starting point for new web apps:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--surface: #ffffff;
|
||||
--surface-2: #f9fafb;
|
||||
--border: rgba(34, 36, 38, 0.15);
|
||||
--border-lite: rgba(34, 36, 38, 0.1);
|
||||
--ink: rgba(0, 0, 0, 0.87);
|
||||
--muted: rgba(0, 0, 0, 0.6);
|
||||
--accent: #2185d0;
|
||||
--accent-dark: #1678c2;
|
||||
--accent-bg: #dff0ff;
|
||||
--ok: #16ab39;
|
||||
--warn: #f2711c;
|
||||
--crit: #db2828;
|
||||
--header-bg: #1b1c1d;
|
||||
--radius: 4px;
|
||||
--shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15);
|
||||
--content-width: 1500px;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
font: 14px/1.5 Lato, "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 14px 24px;
|
||||
background: var(--header-bg);
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.page-main {
|
||||
width: min(var(--content-width), calc(100vw - 48px));
|
||||
margin: 28px auto 56px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
margin-bottom: 28px;
|
||||
overflow: hidden;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.panel > h2 {
|
||||
margin: 0;
|
||||
padding: 13px 16px;
|
||||
background: var(--surface-2);
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.kv-table,
|
||||
.data-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.kv-table th,
|
||||
.kv-table td,
|
||||
.data-table th,
|
||||
.data-table td {
|
||||
padding: 11px 14px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid var(--border-lite);
|
||||
}
|
||||
|
||||
.kv-table th,
|
||||
.data-table th {
|
||||
background: var(--surface-2);
|
||||
border-top: 0;
|
||||
border-bottom: 1px solid var(--border-lite);
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-table tbody tr:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
display: inline-block;
|
||||
padding: 8px 18px;
|
||||
border: none;
|
||||
border-radius: var(--radius);
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font: inherit;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-primary:hover {
|
||||
background: var(--accent-dark);
|
||||
}
|
||||
|
||||
.header-action {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
border-radius: var(--radius);
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.header-action:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.status-ok { color: var(--ok); }
|
||||
.status-warning { color: var(--warn); }
|
||||
.status-critical { color: var(--crit); }
|
||||
.status-unknown { color: rgba(0, 0, 0, 0.45); }
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.page-main {
|
||||
width: calc(100vw - 24px);
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Copyable Starter HTML
|
||||
|
||||
```html
|
||||
<header class="page-header">
|
||||
<h1>Application Title</h1>
|
||||
<a class="header-action" href="/back">Back</a>
|
||||
</header>
|
||||
|
||||
<main class="page-main">
|
||||
<section class="panel">
|
||||
<h2>Overview</h2>
|
||||
<div class="table-wrap">
|
||||
<table class="kv-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Host</th>
|
||||
<td>server-01</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<td><span class="status-ok">OK</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2>Devices</h2>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Vendor</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>NIC 1</td>
|
||||
<td>Intel</td>
|
||||
<td><span class="status-warning">Warning</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
```
|
||||
Reference in New Issue
Block a user