Architecture
Knitly Architecture
Section titled “Knitly Architecture”Project Structure
Section titled “Project Structure”The knitly-app/knitly repository is a Bun workspace. Its root holds the frontend, server, optional custom extensions, and deploy configs:
knitly/├── frontend/ # Preact SPA│ ├── src/│ │ ├── api/ # API client and query keys│ │ ├── routes/ # Router routes│ │ ├── components/ # UI components│ │ ├── hooks/ # Custom hooks│ │ ├── stores/ # Zustand stores│ │ └── utils/ # Utility functions│ └── dist/ # Built frontend (Vite)│├── server/ # Hono API server│ └── src/│ ├── routes/ # API route handlers│ ├── middleware/ # Request middleware│ ├── lib/ # Database, security, media, etc.│ └── __tests__/ # API tests│├── custom/ # Optional, gitignored per-deployment extensions│ ├── server/ # Custom API routes│ └── frontend/ # Custom frontend code│├── deploy/ # Deployment configs│ ├── Caddyfile.example│ ├── env.production.example│ ├── knitly.service # systemd unit│ └── knitly.openrc # OpenRC service│├── Dockerfile└── docker-compose.ymlFrontend Architecture
Section titled “Frontend Architecture”Tech Stack
Section titled “Tech Stack”- Framework: Preact 10.27+ (React-compatible, smaller bundle)
- State: TanStack Query (server state), Zustand (client state)
- Routing: @tanstack/react-router v1.157+
- Styling: Tailwind CSS v4.1+
- Build: Vite 7.2+
Directory Structure
Section titled “Directory Structure”frontend/src/├── api/│ ├── client.ts # API request wrapper│ └── queryKeys.ts # Query key factories├── routes/│ ├── index.ts # Route exports│ ├── constants.ts # Route configuration│ └── [routes].tsx # Individual route components├── components/│ ├── Navigation.tsx│ ├── PostCard.tsx│ ├── ProfileCard.tsx│ ├── CreatePostModal.tsx│ └── ...├── hooks/│ ├── useAuth.ts│ ├── usePosts.ts│ ├── useFollow.ts│ └── index.ts├── stores/│ ├── ui.ts # Global UI state│ └── lightbox.ts # Lightbox state├── utils/│ ├── avatar.ts│ ├── markdown.ts│ ├── time.ts│ └── inviter.ts└── test/ ├── unit/ # Unit tests └── component/ # Component testsState Management Pattern
Section titled “State Management Pattern”Server State (TanStack Query):
- All API data fetches use TanStack Query
- Query keys defined in
src/api/queryKeys.ts - No duplicate state in useState/Zustand
Client State (Zustand):
- Global UI state:
src/stores/ui.ts - Lightbox state:
src/stores/lightbox.ts - Single source of truth per concern
No useCallback or useEffect unless syncing with external systems
Backend Architecture
Section titled “Backend Architecture”Tech Stack
Section titled “Tech Stack”- Framework: Hono 4.7+
- Runtime: Bun
- Database: SQLite via
bun:sqlite(no ORM; schema created programmatically inlib/db/core.js) - Security: Argon2 (
@node-rs/argon2) for password hashing; session cookies and Bearer API keys for auth
Directory Structure
Section titled “Directory Structure”server/src/├── routes/│ ├── auth.js # Authentication endpoints│ ├── users.js # User management│ ├── posts.js # Post CRUD│ ├── feed.js # Feed retrieval│ ├── notifications.js│ ├── search.js│ ├── invites.js│ ├── admin.js # Admin endpoints│ ├── media.js # Media upload/download│ ├── circles.js│ ├── settings.js│ ├── chat.js│ └── setup.js # First-time setup├── middleware/│ ├── auth.js # Session verification│ ├── rateLimit.js # Rate limiting│ └── security.js # Security headers├── lib/│ ├── db/ # Database access; core.js defines the schema│ ├── security.js # Password hashing, token generation│ ├── media.js # File storage abstraction (local or S3)│ ├── email.js # Email sending (Resend)│ ├── formatters.js # Response shaping│ └── logging.js├── seed.js # Admin seed├── seed-dev.js # Admin + test users└── __tests__/ # API testsDatabase Schema
Section titled “Database Schema”Tables:
users- User and bot accountssessions- Active sessionsapi_keys- Bearer keys for bot accountsposts,post_media,post_circles- Moments and their attachments/scopingcomments,reactions- Post engagementpolls,poll_options,poll_votes- Pollsfollows- Follow graphnotifications- User notificationsinvites- Invite tokenscircles,circle_members- Private groups and membershipchat_messages,chat_presence- The Lobbypassword_reset_tokens,email_change_tokens- Self-service auth flowssettings- Instance settings (name, logo icon)audit_log- Admin/moderator actions
API Middleware Pipeline
Section titled “API Middleware Pipeline”Request → Logger → Security Headers → Rate Limit → Route HandlerCustom Extensions System
Section titled “Custom Extensions System”The optional custom/ directory adds deployment-specific features without forking. It is gitignored, so the public repository ships no built-in extensions.
Loading:
- Server:
app.jsdynamically importscustom/server/index.jsand mounts its exportedcustomRouterat/api/custom. If the file is absent, the import is caught and skipped. - Frontend:
main.tsxandNavigation.tsxuseimport.meta.globoncustom/frontend/index.tsto pull incustomRoutes(route components) andcustomNavItems(nav links).
See Custom Extensions for the full interface.
Deployment Flow
Section titled “Deployment Flow”Development
Section titled “Development”bun run dev # Start frontend + serverProduction Build
Section titled “Production Build”bun run build # Build frontend with Vitebun run start # Start production serverDocker
Section titled “Docker”docker compose up -dSecurity Model
Section titled “Security Model”Authentication
Section titled “Authentication”- Session-based with cookies for human users
- Bearer
knitly_API keys for bot accounts (SHA-256 hashed at rest), resolved by the sameensureSessionmiddleware - Argon2 password hashing
- Secure cookie attributes (httpOnly, secure, sameSite)
Rate Limiting
Section titled “Rate Limiting”- Auth: 5 requests/minute
- Search: 20 requests/minute
- API: 100 requests/minute
Input Sanitization
Section titled “Input Sanitization”- XSS sanitization on posts, comments, search
- SQL parameterized queries
- File upload validation (magic bytes, dimensions)
- whitelist via
ALLOWED_ORIGINSenv var - credentials enabled
Performance Optimizations
Section titled “Performance Optimizations”- Database indexes for common queries
- N+1 query fixes (feed, user posts, search)
- Lazy route loading in frontend
- Vendor splitting with Vite
- Image lazy loading
- TanStack Query caching (staleTime/gcTime)