Files

824 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
## Purpose
This repository contains **Local Image Editor**, a small privacy-friendly browser application for placing one or more image overlays on top of a user-supplied background image and exporting the result at the background image's original resolution.
The application is intentionally simple:
```text
Upload background
↓
Add predefined or custom overlays
↓
Drag / resize / fine-tune coordinates
↓
Download PNG or JPEG
```
This file defines the expectations and constraints for coding agents working in this repository.
Read **README.md** and **PLAN.md** before making non-trivial changes.
---
## Core principles
These are non-negotiable unless the user explicitly changes the product requirements.
1. **User images stay local to the browser.**
- Do not upload user images to a server.
- Do not add analytics that capture image content.
- Do not add cloud storage or third-party image processing.
- Do not send user files to external APIs.
2. **The original image pixel dimensions are the canonical coordinate system.**
- X, Y, width, height, bounds, quick positioning, and export must all be expressed in source-image pixels.
- Browser/display size must never change logical object coordinates.
3. **Do not use a full-resolution interactive Fabric canvas for normal editing.**
- The current editor intentionally uses a smaller backing store plus a Fabric viewport transform.
- This is important for mobile memory usage and large phone photos.
- Full source resolution should only be used transiently when producing the final export.
4. **Export must preserve the exact source dimensions.**
- A 4032×3024 background must produce a 4032×3024 export.
- UI scaling must not affect export resolution or object placement.
5. **The project is frontend-only.**
- Do not introduce a backend, database, authentication, user accounts, or server-side image processing unless explicitly requested.
6. **The repository is public.**
- Never commit secrets or private infrastructure data.
- Do not assume obscurity, minification, Docker images, or frontend environment variables provide secrecy.
7. **Keep the product simple.**
- Prefer a small, understandable implementation over speculative abstractions or feature creep.
---
## Technology baseline
Use the existing stack unless the task specifically requires a change:
- Vue 3
- Vite
- TypeScript
- Fabric.js
- Node.js 22+
- nginx
- Docker / Docker Compose
Do not downgrade Fabric below the security baseline already enforced by the repository checks.
Avoid adding dependencies when the browser, Vue, Fabric, or a small local helper can solve the problem cleanly.
If adding or changing dependencies:
- update `package.json`;
- update and commit `package-lock.json`;
- run the full checks;
- inspect the dependency for current security issues;
- avoid packages that add remote runtime dependencies or tracking.
---
## Repository map
Important files and responsibilities:
```text
src/
├── App.vue
├── main.ts
├── components/
│ ├── BackgroundUpload.vue
│ ├── ExportControls.vue
│ ├── ImageEditor.vue
│ ├── OverlayControls.vue
│ └── OverlayPicker.vue
├── composables/
│ ├── useFabricEditor.ts
│ └── useLocale.ts
├── types/
│ └── editor.ts
├── utils/
│ ├── editorMath.ts
│ ├── imageFiles.ts
│ └── overlayConfig.ts
└── styles/
└── main.css
public/
└── overlays/
├── overlays.json
└── <overlay image files>
tests/
├── editorMath.test.ts
└── overlayConfig.test.ts
scripts/
├── quality-check.mjs
└── security-check.mjs
```
### Ownership boundaries
Keep these boundaries intact:
- **`useFabricEditor.ts`** owns Fabric.js lifecycle and canvas manipulation.
- **`editorMath.ts`** contains pure coordinate, size, bounds, and positioning logic.
- **`overlayConfig.ts`** validates the runtime overlay library.
- Vue components should primarily handle UI, props/events, and presentation.
- Do not spread direct Fabric manipulation throughout multiple components.
If new Fabric behavior is needed, prefer adding it to `useFabricEditor.ts` or a focused utility rather than manipulating the canvas directly from a UI component.
---
## Development commands
Install dependencies:
```sh
npm ci
```
Run locally:
```sh
npm run dev
```
Type check:
```sh
npm run type-check
```
Run tests:
```sh
npm test
```
Repository quality checks:
```sh
npm run lint
```
Security checks:
```sh
npm run security-check
```
Run all non-build checks:
```sh
npm run check
```
Production build:
```sh
npm run build
```
Production dependency audit:
```sh
npm audit --omit=dev --omit=optional --audit-level=high
```
Docker:
```sh
docker compose up --build
```
Before considering a code change complete, normally run:
```sh
npm run check
npm run build
```
If dependencies changed, also run the production dependency audit.
If Docker/nginx files changed, build and validate the container as well.
---
## Required agent workflow
For non-trivial tasks:
1. Read the relevant implementation before editing.
2. Read related tests.
3. Check `README.md` and `PLAN.md` for product constraints.
4. Identify the smallest set of files that should own the change.
5. Preserve the coordinate/rendering model described below.
6. Add or update tests for logic changes.
7. Run `npm run check`.
8. Run `npm run build`.
9. Review the diff for accidental scope expansion, secrets, generated files, and documentation drift.
10. Update `README.md` and/or `PLAN.md` when behavior, deployment, architecture, supported formats, or security assumptions change.
Do not claim a check passed unless it was actually run.
If the local environment prevents a check from running, state exactly which check could not be completed and why.
---
## Coordinate and rendering model
This is the most important technical invariant in the project.
Assume a source image is:
```text
4032 × 3024
```
while the editor is shown at:
```text
900 × 675
```
Objects still use logical coordinates such as:
```text
x = 3200
y = 80
width = 700
```
Those values are **source-image pixels**, not screen pixels.
### Interactive editing
The interactive Fabric canvas should use a display-sized backing store and a viewport transform:
```text
logical scene: 4032 × 3024
interactive backing: 900 × 675
viewport scale: 900 / 4032
```
Do not regress to allocating one or more 4032×3024 Fabric canvases during normal editing.
### Browser resize
Resizing the browser or editor container may change the viewport/display scale.
It must **not** change:
- object X/Y;
- object logical width/height;
- background logical dimensions;
- exported coordinates.
Use container-based resize behavior. Prefer `ResizeObserver` for editor layout changes rather than relying only on `window.resize`.
### Export
Export must temporarily render at source resolution and then restore the interactive editor state.
Any export implementation must:
- preserve the original background dimensions;
- preserve overlay transforms;
- hide Fabric controls/selection from output;
- restore selection and viewport state in `finally`;
- handle allocation/encoding failures gracefully;
- avoid leaving the editor in a modified state after failure.
Prefer asynchronous Blob-based downloads over large synchronous Base64 URLs.
For JPEG export, explicitly flatten transparency onto white unless product requirements change.
---
## Fabric.js rules
### Background
The background image:
- is not a normal editable overlay;
- must be non-selectable;
- must be non-evented;
- defines the logical canvas dimensions.
Replacing the background clears the current composition, so preserve the existing user confirmation behavior whenever overlays exist.
### Overlays
Overlay objects are independent Fabric image objects.
Each must:
- have a stable internal ID;
- have a human-readable name;
- be independently selectable;
- support drag and uniform resize;
- preserve aspect ratio;
- stay within background bounds;
- be removable.
For the MVP:
- rotation is disabled;
- skewing is disabled;
- flipping should not occur;
- edge-only non-uniform scaling controls should remain disabled.
Do not silently re-enable distortion controls.
### Transform updates
When moving or resizing an overlay:
- enforce uniform scale;
- clamp it into the logical background bounds;
- call the relevant Fabric coordinate update methods;
- publish the updated selection values;
- request rendering only as needed.
Do not assume `object.width` is the rendered width. Fabric source dimensions and transformed/scaled dimensions are different concepts.
### Async image loading
Background and overlay decoding are asynchronous.
Preserve the generation/invalidation logic so stale image loads cannot overwrite newer user actions.
A background replacement must invalidate overlay loads started for the previous background.
If adding new asynchronous editor operations, design them so the latest user action wins.
### Fabric lifecycle
Use one controlled Fabric canvas per editor instance.
On component teardown:
- remove/clean listeners as needed;
- dispose the Fabric canvas;
- avoid stale references.
Do not repeatedly recreate Fabric canvases during normal Vue updates.
---
## Bounds and sizing
Pure transform rules belong in `src/utils/editorMath.ts` where possible.
Overlay bounds should normally satisfy:
```text
x >= 0
y >= 0
x + width <= backgroundWidth
y + height <= backgroundHeight
```
Manual numeric inputs, drag, resize, and quick-position actions must all obey the same rules.
Do not implement separate inconsistent bounds algorithms in different components.
Default overlay placement is intentionally resolution-independent:
- default width is proportional to background width;
- margin is proportional to image dimensions;
- default position is near the top-right corner.
If these defaults change, add/update tests.
---
## Supported image formats
The current supported formats are:
- PNG
- JPEG
- WebP
Keep validation centralized in `src/utils/imageFiles.ts`.
Do not add SVG support casually.
If SVG support is explicitly requested, treat it as a deliberate feature:
- review current Fabric SVG security considerations;
- update validation;
- add tests;
- update CSP assumptions if relevant;
- update README/PLAN.
Do not trust only file extensions for user uploads.
---
## Object URLs and browser resources
Custom background and overlay files remain local.
If using `URL.createObjectURL()`:
- revoke URLs after decoding or when no longer needed;
- do not leak object URLs across repeated uploads;
- do not revoke an object URL before Fabric/image decoding has completed.
Avoid retaining large decoded images or canvases unnecessarily.
Performance on mobile Safari and large phone photos is a first-class concern.
---
## Overlay library
Runtime predefined overlays live under:
```text
public/overlays/
```
The library is configured by:
```text
public/overlays/overlays.json
```
Example:
```json
{
"id": "crr-logo",
"name": "CRR Logo",
"file": "crr-logo.png"
}
```
The runtime config intentionally accepts only simple local PNG/JPEG/WebP filenames.
Do not loosen validation to arbitrary URLs or nested paths without a clear requirement and security review.
Current validation should reject:
- empty fields;
- duplicate IDs;
- duplicate files;
- remote URLs;
- nested paths;
- path traversal;
- unsupported file extensions.
Adding a predefined overlay should normally require only:
1. copying the image into the overlay directory;
2. adding an entry to `overlays.json`.
Do not require a Vue rebuild just to add a new runtime overlay.
The Docker/nginx configuration intentionally makes `/overlays/` revalidate rather than cache for a week, because deployed logos may be replaced without rebuilding the application.
---
## UI and accessibility
The editor must work on:
- desktop;
- tablet;
- mobile;
- mouse;
- touch;
- keyboard for non-drag alternatives.
Do not make drag the only way to manipulate an object.
Maintain:
- numeric X control;
- numeric Y control;
- numeric width control;
- accessible overlay selection;
- quick corner buttons;
- visible focus states;
- useful labels.
If multiple overlays exist, keyboard users must have a way to select an existing overlay without clicking the canvas.
Do not introduce horizontal page scrolling for normal mobile layouts.
The editor is the primary visual element. Avoid turning the app into a complex dashboard.
---
## Internationalization
The interface supports:
- English;
- Portuguese (Portugal).
User-visible application strings should go through `useLocale.ts`.
Do not hardcode new English UI text directly in components unless it is truly non-user-visible.
When adding a string:
- add the English translation;
- add the PT-PT translation;
- use Portuguese from Portugal, not Brazilian Portuguese;
- preserve proper accents and spelling.
Examples of preferred PT-PT wording:
- `ficheiro`
- `imagem`
- `sobreposição`
- `carregar`
- `descarregar`
- `área de edição`
Avoid Brazilian-specific UI vocabulary where a natural PT-PT alternative exists.
ARIA labels that are user-facing should also be translated.
---
## Security and public-repository rules
This repository is public.
### Secrets
Never commit:
- API keys;
- passwords;
- access tokens;
- private keys;
- private certificates;
- deployment credentials;
- private infrastructure details that are intended to remain private.
Real local environment files must remain ignored.
The repository should contain:
```text
.env.example
```
with safe example/non-secret values only.
### Frontend environment variables
Do not put secrets in Vite/frontend variables.
Anything bundled into browser JavaScript is public.
In particular:
```text
VITE_*
```
must never be treated as secret storage.
The current project intentionally avoids Vite deployment configuration where runtime static configuration is simpler.
If a future feature requires a real secret, do not "hide" it in the frontend. Propose a server-side boundary or a deployment secret mechanism.
### External services
Do not add:
- telemetry;
- analytics;
- remote fonts;
- remote scripts;
- CDN runtime dependencies;
- third-party upload services;
unless explicitly requested and reviewed against privacy/CSP requirements.
The current restrictive nginx Content Security Policy is intentional.
### Secret scanning
Preserve and run:
```sh
npm run security-check
```
Do not change secret scanning to print actual discovered secret values into CI logs. Report filenames/types, not secret contents.
### Dependency security
Do not weaken the Fabric minimum-version security check.
Keep nginx on a maintained/patched release.
When changing dependencies, inspect current advisories and run the dependency audit.
---
## Docker and nginx
The production image is a static nginx deployment.
Keep it that way unless requirements change.
Important behavior:
- `.env` must not be copied into the image;
- overlay directory is mounted read-only;
- runtime overlays are served from `/overlays/`;
- overlay files should revalidate so replacements appear promptly;
- the app is normally deployed at the root of a hostname;
- security headers and CSP are intentional.
If changing nginx:
- preserve SPA/static asset behavior;
- preserve overlay runtime behavior;
- validate the nginx configuration;
- review CSP implications of any new browser capability.
Do not hardcode private domains, tokens, or infrastructure credentials in Docker/nginx files.
---
## Testing expectations
Tests should focus on behavior that is easy to regress.
Pure logic belongs in utilities so it can be tested without a browser where possible.
At minimum, add/update tests when changing:
- coordinate scaling;
- bounds;
- resize behavior;
- corner positioning;
- default overlay sizing;
- overlay configuration parsing/validation.
For editor behavior that depends on Fabric/browser APIs, prefer focused browser/integration tests if a unit test would only mock away the behavior being verified.
Important scenarios include:
```text
1280 × 1280
1920 × 1080
1080 × 1920
4032 × 3024
```
Verify that browser/editor resizing does not change logical coordinates.
When touching export logic, verify:
- PNG output dimensions;
- JPEG output dimensions;
- object placement;
- multiple overlay stacking;
- absence of Fabric controls;
- editor state restoration after export;
- failure handling where practical.
---
## Code style
Follow the existing TypeScript/Vue style.
General expectations:
- strict TypeScript;
- explicit types at important boundaries;
- small focused functions;
- pure helpers for math/validation;
- avoid `any`;
- avoid non-null assertions unless the invariant is genuinely guaranteed;
- avoid duplicated logic;
- prefer early returns for invalid state;
- keep async error handling explicit;
- clean up browser resources and listeners.
Do not add abstractions solely to anticipate hypothetical future features.
Do not commit:
- `dist/`;
- `node_modules/`;
- local `.env`;
- editor/IDE junk;
- temporary output images;
- debug artifacts.
Keep LF line endings and no trailing whitespace.
---
## Error handling
Errors shown to users should be:
- concise;
- human-readable;
- translated;
- actionable where possible.
Do not expose stack traces in the normal UI.
A failure loading one predefined overlay should not make custom uploads unusable.
Export and decode failures should leave the existing editor state usable.
Do not swallow unexpected errors silently if they prevent the requested action.
---
## Scope discipline
The following are currently **non-goals** unless explicitly requested:
- authentication;
- user accounts;
- database;
- server-side persistence;
- cloud storage;
- project history;
- full layers panel;
- text editor;
- rotation UI;
- filters;
- cropping;
- image effects;
- collaborative editing;
- admin interface;
- remote APIs.
Potential future features may be mentioned in `PLAN.md`, but their presence there is not permission to implement them during unrelated tasks.
Do not choose or add a software license on the user's behalf unless explicitly requested.
---
## Documentation rules
Update documentation when a change affects what users or deployers need to know.
Update **README.md** for changes to:
- setup;
- commands;
- supported formats;
- deployment;
- overlay configuration;
- privacy/security behavior;
- browser-visible behavior.
Update **PLAN.md** for changes to:
- architecture;
- requirements;
- acceptance criteria;
- project scope;
- implementation direction.
Keep documentation aligned with actual code. Do not document features that are not implemented.
---
## Definition of done
A change is normally complete when:
- the requested behavior is implemented;
- core product invariants remain intact;
- relevant tests are added or updated;
- TypeScript passes;
- tests pass;
- repository quality checks pass;
- security checks pass;
- production build passes;
- dependency audit is reviewed if dependencies changed;
- Docker/nginx is validated if deployment files changed;
- no secrets or generated artifacts were introduced;
- README/PLAN are updated when needed;
- the final diff contains no unrelated refactors.
The goal is not merely to make the requested change work once. It should remain correct for large images, mobile devices, multiple overlays, public deployment, and pixel-accurate export.