# LinkSyncServer - Design Documentation ## Architecture Overview LinkSyncServer is a Python/FastAPI web application with PostgreSQL as the database, designed for bookmark management with advanced collection and query capabilities. ### Tech Stack | Component | Technology | |-----------|------------| | Framework | FastAPI | | ORM | SQLAlchemy | | Authentication | JWT (PyJWT) | | Database | PostgreSQL 15+ | | Templates | Jinja2 | | Static Files | Native static serving | | Containerization | Docker | ### Directory Structure ``` LinkSyncServer/ ├── README.md ├── TODOs.txt ├── design.md ├── tasks.md ├── AGENTS.md ├── docker-compose.yml ├── Dockerfile ├── requirements.txt ├── pyproject.toml ├── app.py ├── config/ │ ├── settings.py │ └── schema.sql ├── api/ │ ├── __init__.py │ ├── routes.py │ ├── endpoints/ │ │ ├── auth.py │ │ ├── links.py │ │ ├── collections.py │ │ └── queries.py │ ├── parsers/ │ │ ├── __init__.py │ │ └── query_parser.py │ └── serializers/ │ ├── __init__.py │ └── schemas.py ├── models/ │ ├── __init__.py │ ├── base.py │ ├── user.py │ ├── link.py │ ├── collection.py │ └── tag.py ├── queries/ │ ├── __init__.py │ ├── ast.py │ └── executor.py ├── templates/ │ ├── base.html │ ├── layout.html │ ├── links/ │ │ ├── list.html │ │ ├── detail.html │ │ └── create.html │ ├── collections/ │ │ ├── list.html │ │ ├── detail.html │ │ ├── create.html │ │ └── edit.html │ └── auth/ │ ├── login.html │ ├── register.html │ └── forgot_password.html ├── static/ │ ├── css/ │ │ ├── main.css │ │ └── print.css │ ├── js/ │ │ ├── main.js │ │ └── api.js │ └── images/ └── tests/ ├── __init__.py ├── conftest.py ├── test_auth.py ├── test_links.py └── test_collections.py ``` ## Data Models ### User ```python class User(Base): id: UUID username: str (unique, indexed) email: str (unique, indexed) password_hash: str role: Enum('admin', 'user') is_active: bool created_at: datetime updated_at: datetime ``` ### Link ```python class Link(Base): id: UUID url: str (indexed) title: str description: str | None notes: str | None tags: List[UUID] (FK to tags) favicon_url: str | None path: str (folder structure) created_at: datetime updated_at: datetime visit_count: int is_bookmarked: bool source_set_id: UUID | None (FK to collections) user_id: UUID (FK, nullable for shared links) ``` ### Collection ```python class Collection(Base): id: UUID name: str (unique per user) description: str | None query_type: Enum('static', 'dynamic') query_expression: str | None # SQL-like query string links: List[UUID] # For static collections only is_public: bool created_by: UUID (FK to users) created_at: datetime updated_at: datetime ``` ### Tag ```python class Tag(Base): id: UUID name: str (unique) color: str | None description: str | None created_at: datetime updated_at: datetime ``` ### AuditLog ```python class AuditLog(Base): id: UUID user_id: UUID (FK, nullable for system events) action: str entity_type: str entity_id: UUID old_value: str | None new_value: str | None ip_address: str created_at: datetime ``` ## Query Engine Design ### Query Syntax ``` ('term1', 'term2') OR tagA AND tagB XOR url:example.com ``` ### Parser Architecture ``` Input String ↓ Tokenize ↓ Build AST Node Tree ↓ Validate AST ↓ Serialize to JSON (for storage) ``` ### AST Node Types | Node Type | Description | |-----------|-------------| | `TermSet` | Tuple of search terms: `('term1', 'term2')` | | `TagFilter` | Tag-based filter: `tagA` | | `FieldFilter` | Field value filter: `url:example.com` | | `AND` | Set intersection | | `OR` | Set union | | `XOR` | Set difference | | `NOT` | Negation | ### Executor Flow ``` 1. Parse query expression 2. Validate AST 3. Build SQL from AST 4. Execute against PostgreSQL 5. Return result set 6. Serialize for client ``` ### Full-Text Search PostgreSQL full-text search enabled via: ```sql CREATE INDEX links_fts_idx ON links USING GIN (to_tsvector('english', url || ' ' || title || ' ' || description || ' ' || notes)); ``` Query terms converted to tsquery and matched. ## API Design ### Authentication Flow ``` 1. POST /api/auth/register/ - Create new account 2. POST /api/auth/login/ - Get JWT token 3. Include Authorization header in all API requests 4. Token validated per request ``` ### Link Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | GET | /api/links/ | List links (paginated) | | GET | /api/links/{id}/ | Get link details | | POST | /api/links/ | Create link | | PUT | /api/links/{id}/ | Update link | | DELETE | /api/links/{id}/ | Delete link | ### Collection Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | GET | /api/collections/ | List collections | | GET | /api/collections/{id}/ | Get collection | | POST | /api/collections/ | Create collection | | PUT | /api/collections/{id}/ | Update collection | | DELETE | /api/collections/{id}/ | Delete collection | | POST | /api/collections/{id}/refresh/ | Re-evaluate dynamic | ### Query Execution Endpoint ``` POST /api/queries/execute/ { "expression": "('work', 'dev') OR tag:work", "static_collections": [...] } → Returns filtered link list ``` ## Security Design ### Password Storage - bcrypt hashing with cost factor 12 - Passwords never logged or exposed ### JWT Tokens - HS256 algorithm - 24-hour expiration - Refresh token pattern for long sessions ### Rate Limiting - 100 requests per minute per IP - 10 login attempts per hour per IP ### CORS - Configurable origin whitelist - Credentials allowed for extension ## Docker Compose Design ### Services | Service | Image | Purpose | |---------|-------|---------| | web | built from Dockerfile | FastAPI app | | db | postgres:15-alpine | PostgreSQL database | ### Environment Variables ``` DATABASE_URL=postgresql://linksync:password@db:5432/linksync SECRET_KEY= ADMIN_USERNAME=admin ADMIN_PASSWORD= DEBUG=False HOST=0.0.0.0 PORT=5000 CORS_ORIGINS=http://localhost:5555 ``` ### Health Checks ```yaml healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000/health"] interval: 30s timeout: 10s retries: 3 ``` ## Sync Protocol Design ### Sync Endpoint ``` POST /api/sync/ Request: { "type": "bi-directional|browser-authoritative|server-authoritative", "deletions_enabled": true, "links": [ { "id": "uuid", "url": "https://...", "title": "...", ... all fields } ] } Response: { "actions": [ {"type": "create", "link_id": "..."}, {"type": "update", "link_id": "..."}, {"type": "delete", "link_id": "..."} ] } ``` ### Conflict Resolution Priority based on sync mode: 1. **Bi-directional**: Keep both versions, merge metadata 2. **Browser Authoritative**: Overwrite with browser data 3. **Server Authoritative**: Download only, no overwrites ## Template Design ### Layout Components ```html {% block title %}LinkSync{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% endblock %}
``` ### Responsive Design - Mobile-first CSS - Breakpoints: 768px, 1024px - Touch-friendly UI controls