Skip to content

Commit 9463302

Browse files
authored
Merge pull request #16 from RZEROSTERN/feat/add-claude-md
Added CLAUDE.md as source of truth for AI assisted development
2 parents c198b67 + 9dfff55 commit 9463302

3 files changed

Lines changed: 241 additions & 8 deletions

File tree

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ build/
7878
**/claude/**/claude-*.log
7979
**/.claude/
8080
CLAUDE.local.md
81-
CLAUDE.md
8281

8382
# FVM Version Cache
8483
.fvm/

CLAUDE.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What This Is
6+
7+
A Flutter/Dart package providing a **viewer** (`EditorJSView`) and **editor** (`EditorJSEditor`) widget compatible with the [EditorJS](https://editorjs.io/) JSON schema. Currently being refactored to Clean Architecture + SOLID for production readiness.
8+
9+
## Commands
10+
11+
```bash
12+
# Install dependencies
13+
fvm flutter pub get
14+
15+
# Run the demo app
16+
cd demo && fvm flutter run
17+
18+
# Run tests
19+
fvm flutter test
20+
21+
# Analyze code
22+
fvm flutter analyze
23+
24+
# Format code
25+
dart format lib/ test/ demo/lib/
26+
```
27+
28+
Single test file:
29+
```bash
30+
fvm flutter test test/editorjs_flutter_test.dart
31+
```
32+
33+
> All Flutter commands must use `fvm flutter ...` — never plain `flutter`.
34+
35+
---
36+
37+
## Architecture
38+
39+
The package follows **Clean Architecture** with three strict layers. Dependencies only flow inward (presentation → data → domain). No new external dependencies — only `flutter_html`, `image_picker`, `url_launcher`, and Flutter's built-in `ChangeNotifier`.
40+
41+
```
42+
lib/src/
43+
├── domain/ ← pure Dart, zero Flutter imports
44+
│ ├── entities/ ← BlockEntity (abstract), BlockDocument, StyleConfig, one class per block type
45+
│ ├── repositories/ ← DocumentRepository (abstract interface)
46+
│ └── usecases/ ← ParseDocument, SerializeDocument
47+
├── data/ ← JSON parsing only
48+
│ ├── mappers/ ← BlockMapper<T> (abstract) + one concrete mapper per block type
49+
│ ├── datasources/ ← JsonDocumentSource implements DocumentRepository
50+
│ └── registry/ ← BlockTypeRegistry — the OCP extension point for custom block types
51+
└── presentation/ ← Flutter widgets
52+
├── controller/ ← EditorController (ChangeNotifier, List<BlockEntity>, getContent())
53+
├── config/ ← EditorConfig (wires registries + styleConfig)
54+
├── registry/ ← BlockRendererRegistry (maps type strings → builder functions)
55+
├── blocks/ ← base_block_renderer.dart, base_block_editor.dart, one subdir per block type
56+
└── widgets/ ← EditorJSView, EditorJSEditor, EditorJSToolbar (thin delegators)
57+
```
58+
59+
### Key Contracts
60+
61+
| Contract | Layer | Responsibility |
62+
|---|---|---|
63+
| `BlockEntity` | Domain | Abstract base: `String get type`, `Map<String,dynamic> toJson()` |
64+
| `DocumentRepository` | Domain | `BlockDocument parse(String)`, `String serialize(BlockDocument)` |
65+
| `BlockMapper<T>` | Data | `String get supportedType`, `T fromJson(Map<String,dynamic>)` |
66+
| `BlockRenderer<T>` | Presentation | Abstract `StatelessWidget` with `T block`, `StyleConfig? styleConfig` |
67+
| `BlockEditor<T>` | Presentation | Abstract `StatefulWidget` with `T block`, `ValueChanged<T> onChanged` |
68+
69+
### EditorController
70+
71+
Replaces the previous `List<Widget>` anti-pattern. The editor stores **data, not widgets**.
72+
73+
```dart
74+
class EditorController extends ChangeNotifier {
75+
List<BlockEntity> get blocks
76+
void addBlock(BlockEntity block)
77+
void updateBlock(int index, BlockEntity updated)
78+
void removeBlock(int index)
79+
void moveBlock(int from, int to)
80+
String getContent() // returns EditorJS-compliant JSON string
81+
}
82+
```
83+
84+
### Block Registry Pattern (Open/Closed Principle)
85+
86+
New block types are added by registering into the registries — **never by editing switch statements**.
87+
88+
```dart
89+
// Adding a custom block — zero changes to core package files
90+
final config = EditorConfig(
91+
typeRegistry: BlockTypeRegistry()..register(MyMapper()),
92+
rendererRegistry: BlockRendererRegistry()
93+
..registerRenderer('my_type', (b, s) => MyRenderer(block: b as MyBlock))
94+
..registerEditor('my_type', (b, cb) => MyEditor(block: b as MyBlock, onChanged: cb)),
95+
);
96+
```
97+
98+
### SOLID Rules (must be enforced in all PRs)
99+
100+
- **SRP**: Each block type has its own entity, mapper, renderer, and editor — no god objects
101+
- **OCP**: Core files never change to support new block types; extend via registry
102+
- **LSP**: All `BlockRenderer<T>` and `BlockEditor<T>` subclasses are interchangeable
103+
- **ISP**: Viewer callers only need `EditorJSView` + optional `EditorConfig` — never `EditorController`
104+
- **DIP**: `EditorJSToolbar` communicates only via `EditorController`, never holds a parent widget reference
105+
106+
---
107+
108+
## Supported Block Types
109+
110+
| Block | Viewer | Editor | Notes |
111+
|---|---|---|---|
112+
| `header` | H1–H6 | Yes | |
113+
| `paragraph` | HTML via flutter_html | Yes | |
114+
| `list` | Flat ordered/unordered | Yes | Nested lists not yet supported |
115+
| `delimiter` | Divider | Yes | |
116+
| `image` | Network URL | Yes | caption/border/stretch not yet rendered |
117+
| `quote` | Planned | Planned | |
118+
| `code` | Planned | Planned | |
119+
| `table` | Planned | Planned | |
120+
| `checklist` | Planned | Planned | |
121+
122+
---
123+
124+
## Public API
125+
126+
`lib/editorjs_flutter.dart` is the sole entry point. It exports:
127+
128+
- **Widgets**: `EditorJSView`, `EditorJSEditor`
129+
- **Controller**: `EditorController`
130+
- **Config**: `EditorConfig`
131+
- **Registries**: `BlockTypeRegistry`, `BlockRendererRegistry`
132+
- **Contracts** (for custom block authors): `BlockMapper`, `BlockRenderer`, `BlockEditor`, `BlockEntity`, `BlockDocument`, `StyleConfig`
133+
- **Built-in entities**: `HeaderBlock`, `ParagraphBlock`, `ListBlock`, `DelimiterBlock`, `ImageBlock`
134+
135+
Nothing from `lib/src/` should be imported directly by consumers.
136+
137+
---
138+
139+
## Implementation Order
140+
141+
When building new features, always work bottom-up:
142+
143+
1. Domain entity (pure Dart, no Flutter)
144+
2. `BlockMapper<T>` in data layer + register in `BlockTypeRegistry`
145+
3. `BlockRenderer<T>` + `BlockEditor<T>` in presentation + register in `BlockRendererRegistry`
146+
4. Unit tests for mapper, widget tests for renderer
147+
148+
---
149+
150+
## Key Source Locations
151+
152+
- `lib/editorjs_flutter.dart` — public API barrel file
153+
- `lib/src/domain/entities/` — block entity classes
154+
- `lib/src/data/registry/block_type_registry.dart` — JSON parsing extension point
155+
- `lib/src/presentation/registry/block_renderer_registry.dart` — rendering extension point
156+
- `lib/src/presentation/controller/editor_controller.dart` — editor state + `getContent()`
157+
- `lib/src/presentation/widgets/` — thin shell widgets
158+
- `demo/lib/main.dart` — viewer usage example
159+
- `demo/lib/createnote.dart` — editor usage example
160+
- `demo/test_data/` — sample EditorJS JSON and styles JSON
161+
162+
## Git Workflow
163+
164+
**This repo has branch protection. Direct commits to `master` are not allowed.**
165+
166+
### Before starting any coding task
167+
168+
1. Ensure `master` is up to date and create a new branch:
169+
```bash
170+
git checkout master
171+
git pull
172+
git checkout -b <prefix>/<short-description>
173+
```
174+
2. Use these branch name prefixes:
175+
- `feat/` — new feature or block type
176+
- `fix/` — bug fix
177+
- `refactor/` — internal restructuring with no behaviour change
178+
- `chore/` — dependency bumps, tooling, docs
179+
180+
### Before finishing any coding task
181+
182+
1. Run `fvm flutter analyze` — must report **no issues** before marking work done.
183+
2. Generate a `PR_DESCRIPTION.md` file at the repo root (see template below).
184+
3. All changes go to `master` via Pull Request only — never push directly.
185+
4. Delete `PR_DESCRIPTION.md` after the PR is merged.
186+
187+
### PR_DESCRIPTION.md template
188+
189+
```markdown
190+
## Title
191+
<concise PR title>
192+
193+
## Type of change
194+
- [ ] Bug fix
195+
- [ ] New feature
196+
- [ ] Refactor
197+
- [ ] Chore / dependency update
198+
- [ ] Documentation
199+
200+
## Summary
201+
- <bullet point summary of what changed and why>
202+
203+
## Breaking changes
204+
<list any public API changes, or "None">
205+
206+
## Migration notes
207+
<instructions for consumers upgrading, or "None">
208+
209+
## Test plan
210+
- [ ] `fvm flutter analyze` passes with no issues
211+
- [ ] Relevant unit/widget tests added or updated
212+
- [ ] Demo app tested manually on at least one platform
213+
```
214+
215+
---
216+
217+
## Versioning
218+
219+
Current version: `0.1.0` (in `pubspec.yaml`).
220+
221+
When making changes, always update `CHANGELOG.md` with a new entry at the top following the existing format:
222+
- Bump the patch version for bug fixes
223+
- Bump the minor version for new features or breaking API changes
224+
- Keep `pubspec.yaml` version in sync with `CHANGELOG.md`
225+
226+
## Known Issues / Backlog
227+
228+
- Image `caption`, `withBorder`, `stretched`, `withBackground` fields parsed but not rendered
229+
- Nested lists not supported
230+
- No HTML sanitization before passing to `flutter_html` (XSS risk with untrusted JSON)
231+
- All tests are commented out — need full test coverage
232+
- `quote`, `code`, `table`, `checklist` blocks not yet implemented

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,15 @@ AI tools (including Claude Code) are permitted to assist with contributions to t
181181

182182
The following rules apply when using Claude Code (`claude` CLI) on this repository:
183183

184-
1. **No autonomous commits.** Claude Code must never commit or push changes without explicit human instruction. Every commit requires a human to review the diff and approve it first.
185-
2. **No force pushes.** Claude Code must never run `git push --force` or any destructive git operation (`reset --hard`, `branch -D`, etc.) without explicit human confirmation.
186-
3. **Scope discipline.** Claude Code must only modify files directly related to the described task. It must not refactor, reformat, or add documentation to files it was not asked to touch.
187-
4. **No secret handling.** Claude Code must never read, write, or commit files that may contain credentials, API keys, or environment secrets (`.env`, `*.pem`, `*.key`, etc.).
188-
5. **Dependency changes require approval.** Any addition, removal, or version change to dependencies in `pubspec.yaml` must be explicitly requested by the human contributor before being applied.
189-
6. **Architecture changes require prior agreement.** Changes that affect the package's public API, layer boundaries, or the block registry must be discussed and agreed upon before Claude Code implements them.
190-
7. **CLAUDE.md is the source of truth.** Claude Code must read and follow `CLAUDE.md` at the start of every session. Any conflict between `CLAUDE.md` and a user instruction must be surfaced to the human before proceeding.
184+
1. **Branch before coding.** Claude Code must create and checkout a new branch from `master` before writing any code. Branch names must follow the `feat/`, `fix/`, `refactor/`, or `chore/` prefix convention. Direct commits to `master` are never allowed.
185+
2. **Generate a PR description before finishing.** At the end of every coding session, Claude Code must produce a `PR_DESCRIPTION.md` file at the repo root summarising the changes (title, type of change, summary, breaking changes, migration notes, test plan checklist). This file is ephemeral — delete it after the PR is merged.
186+
3. **No autonomous commits.** Claude Code must never commit or push changes without explicit human instruction. Every commit requires a human to review the diff and approve it first.
187+
4. **No force pushes.** Claude Code must never run `git push --force` or any destructive git operation (`reset --hard`, `branch -D`, etc.) without explicit human confirmation.
188+
5. **Scope discipline.** Claude Code must only modify files directly related to the described task. It must not refactor, reformat, or add documentation to files it was not asked to touch.
189+
6. **No secret handling.** Claude Code must never read, write, or commit files that may contain credentials, API keys, or environment secrets (`.env`, `*.pem`, `*.key`, etc.).
190+
7. **Dependency changes require approval.** Any addition, removal, or version change to dependencies in `pubspec.yaml` must be explicitly requested by the human contributor before being applied.
191+
8. **Architecture changes require prior agreement.** Changes that affect the package's public API, layer boundaries, or the block registry must be discussed and agreed upon before Claude Code implements them.
192+
9. **CLAUDE.md is the source of truth.** Claude Code must read and follow `CLAUDE.md` at the start of every session. Any conflict between `CLAUDE.md` and a user instruction must be surfaced to the human before proceeding.
191193

192194
## Committer responsibility disclaimer
193195

0 commit comments

Comments
 (0)