For anyone granted permission to work on the SajiloCloud codebase.
First, read CONTRIBUTING.md. SajiloCloud is proprietary - you need explicit written permission from the maintainer before modifying or contributing.
server.py # Entry point - HTTP server, routing, static files
websocket_server.py # Entry point - real-time collaboration server
api_handlers.py # REST API handlers (one function per endpoint)
collaborative_manager.py # Canvas/scratchpad persistence (JSON on disk)
dns_service.py # mDNS (.local) registration via zeroconf
audit_logger.py # Writes data/activity_log.json (last 100 entries)
temp_handler.py # Portal data helper (used by api_handlers)
server_control_panel.py # Desktop GUI (Tkinter) that spawns the servers
repro_mdns.py # Standalone mDNS repro/debug script
app.js # Frontend logic (vanilla ES6+)
index.html # SPA shell
styles.css # All styling (glassmorphism, dark/light)
modules/collaborative/ # Canvas + scratchpad frontend modules
images/icons/ # Favicons & site icons
Home/ # Runtime user data (git-ignored)
data/ # Runtime logs (git-ignored)
docs/ # Documentation
server.py subclasses SimpleHTTPRequestHandler. Routing is a chain of
if / elif on the path:
if path == "/api/list":
api_handlers.handle_list(self, parsed, UPLOAD_ROOT, ADMIN_KEY, HIDDEN_FOLDERS, safe_join)Every handler in api_handlers.py is a standalone function - easy to read, easy
to test.
All user-supplied paths go through safe_join() (server.py):
def safe_join(base, *paths):
final_path = os.path.normpath(os.path.join(base, *paths))
if not final_path.startswith(base): # (Windows uses .lower())
raise ValueError(...)Never write a handler that builds a filesystem path from user input without
going through safe_join. This is the main defense against path-traversal.
config.json, Home/**, data/* are runtime data. The repo must always boot
from a fresh clone with defaults. If you add new runtime artifacts, ignore them.
CollaborativeManager owns Home/.collaborative/ - both servers use the same
class, so HTTP saves and WebSocket sessions stay consistent.
git clone https://github.com/arundada9000/sajilocloud.git
cd sajilocloud
pip install -r requirements.txt# HTTP server (auto-reload by restarting)
python server.py
# WebSocket server (for collaborative features)
python websocket_server.pyThere's no auto-reloader - restart the process after Python changes. For frontend changes, just refresh the browser (no build step).
There is no test framework currently. Before you submit anything, at minimum:
- Boot test - both servers start with no errors:
python server.py
python websocket_server.py- Sanity test - from a fresh clone, delete
config.jsonand confirm the server still starts (defaults). - Path test - hit
/api/list?path=../../etcand confirm a500/404, never a file leak. - Smoke test - upload -> rename -> delete -> restore -> purge through the UI.
A CI workflow runs a syntax check on every push - see
.github/workflows/ci.yml.
- Python: 4-space indent, stdlib-first,
black-adjacent formatting. - JavaScript: 2-space indent, vanilla ES6+, template literals.
- HTML/CSS: follow
styles.cssconventions (CSS variables, classes). - Comments: only when they explain why.
- Error handling: handlers catch
Exception, log viaprint, and return a meaningful status - follow that pattern.
- Add a handler function in
api_handlers.py(e.g.handle_my_thing). - Route it in
server.py- addelifbranches indo_GETand/ordo_POST. - Pass only what it needs (
UPLOAD_ROOT,safe_join, managers). - Use
safe_joinfor any path input. - Document it in API.md.
- Boot-test both servers, then run the sanity tests above.
- Persistence: add a method to
CollaborativeManager. - WebSocket: extend
websocket_server.pymessage handling (rooms/broadcast). - Frontend: extend
modules/collaborative/. - Optional HTTP save endpoint:
handle_collaborative_savepattern inapi_handlers.py. - Document in COLLABORATIVE.md.
Keep the dependency list minimal (see requirements.txt / pyproject.toml):
| Package | Where used | Required? |
|---|---|---|
qrcode[pil] |
QR generation | yes |
psutil |
system stats | yes |
websockets |
collaboration server | yes (that feature) |
zeroconf |
.local domains |
no (degrades gracefully) |
Prefer the Python standard library for everything else.
- Branch from
main:git checkout -b feat/your-feature - Commit with conventional prefixes.
- Open a PR using the template.
Remember: this project is proprietary. Only contribute what the maintainer has explicitly approved.