feat: Implement foundation layer with domain entities and repository interfaces

- Add complete domain layer: Note, Vault, WikiLink, Tag, Frontmatter, Graph entities
- Implement repository interfaces for data access abstraction
- Create comprehensive configuration system with YAML and env support
- Add CLI entry point with signal handling and graceful shutdown
- Fix mermaid diagram syntax in design.md (array notation)
- Add CLAUDE.md for development guidance

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev
2025-10-08 10:22:28 +04:00
parent b655c58ba1
commit da289d4a7e
24 changed files with 1840 additions and 7 deletions

79
internal/domain/tag.go Normal file
View File

@@ -0,0 +1,79 @@
package domain
import (
"fmt"
"strings"
)
type Tag struct {
name string
}
func NewTag(name string) (*Tag, error) {
if name == "" {
return nil, fmt.Errorf("tag name cannot be empty")
}
if !strings.HasPrefix(name, "#") {
name = "#" + name
}
if !isValidTagName(name) {
return nil, ErrInvalidTag
}
return &Tag{name: name}, nil
}
func (t *Tag) Name() string {
return t.name
}
func (t *Tag) Parent() *Tag {
if !t.IsNested() {
return nil
}
lastSlash := strings.LastIndex(t.name, "/")
if lastSlash == -1 {
return nil
}
parentName := t.name[:lastSlash]
parent, _ := NewTag(parentName)
return parent
}
func (t *Tag) IsNested() bool {
return strings.Contains(t.name, "/")
}
func (t *Tag) String() string {
return t.name
}
func isValidTagName(name string) bool {
if !strings.HasPrefix(name, "#") {
return false
}
if len(name) <= 1 {
return false
}
tagContent := name[1:]
if strings.Contains(tagContent, " ") {
return false
}
if strings.HasPrefix(tagContent, "/") || strings.HasSuffix(tagContent, "/") {
return false
}
if strings.Contains(tagContent, "//") {
return false
}
return true
}