User Guide · v1.0

Secure Cloud Document Manager — User Guide

A step-by-step manual for signing in, browsing and uploading documents, sharing a folder or a single file with a teammate or the outside world, and staying under your storage quotas — for every role on the platform, employee through admin.

Publisher
Arsi India Info
Web App
https://demo2.arsiindiainfo.com
API Base URL
https://demo2.arsiindiainfo.com/api/v1
Interactive Docs
Local dev only — see §3
Audience
Employees · Managers · Admins
3
User Roles
3
Permission Levels
15
Allowed File Types
100MB
Storage Per User

1. Welcome

Secure Cloud Document Manager is a private-by-default file storage and sharing platform for a fictional company, Meridian Consulting Group — nested folders, drag-and-drop upload with per-type icons and thumbnails, fine-grained sharing (both folders and individual files) with internal teammates or a revocable public link, a Trash with a 30-day restore window, and per-user storage quotas. This guide walks through the platform exactly as an employee, manager, or admin would use it: the web app first, and the underlying API for anyone integrating or testing programmatically.

Who this guide is for Anyone using or evaluating this platform — no prior knowledge of the backend architecture is required. Most people should just use the web app (§2); developers calling the API directly can skip ahead to §3.

2. Two Ways to Use This Platform

There's a real, working web application in front of this platform — you don't need to write any code or run any HTTP requests by hand to try it out.

Web App Recommended

Open https://demo2.arsiindiainfo.com, sign in with a demo account (§4), and click through Browse, Dashboard, and Trash — plus Users and Audit Log if you're an admin. §5 breaks down exactly which screens each role sees.

Raw API / Swagger

Everything the web app does, it does by calling the same JSON API documented in §3 onward. Use this if you're integrating programmatically, testing with curl/Postman, or want exact request/response shapes via the interactive Swagger UI (local dev only).

This guide covers both Every workflow section from §9 onward gives you the web-app steps first ("Via the Web App") and the equivalent raw HTTP call underneath ("Via the API") — use whichever matches how you're exploring the platform.

3. Web App & API Reference

ResourceURL
Web apphttps://demo2.arsiindiainfo.com
API base URLhttps://demo2.arsiindiainfo.com/api/v1
Interactive Swagger docsGET/api/docs (non-production environments only)
Public share linkshttps://demo2.arsiindiainfo.com/s/:token — no login required (§12)

Response envelope

// success
{
  "success": true,
  "data": { /* the actual result */ }
}

// failure
{
  "success": false,
  "error": { "code": "VALIDATION_ERROR", "message": "..." }
}

4. Demo Accounts

The demo seeder creates a full Meridian Consulting Group team — one admin, one manager, one employee — so you can try every role immediately. Every account shares the same password:

RoleEmailPassword
Adminadmin@meridian.testPassw0rd!
Managermanager@meridian.test
Employeeemployee@meridian.test
Demo data notice This is a demo environment seeded with synthetic data — no real documents or customer information. The seeded dataset grants EDITOR on Client Contracts to the Manager and VIEWER on HR Records to the Employee, to demonstrate folder-level permission inheritance (§12) out of the box.

5. Which Screen Is For Which Role

The web app shows the same core navigation to every signed-in user — what any individual folder or document allows depends on the permission granted on it (§12), not on account role. Role only gates two admin-only screens.

ScreenEmployeeManagerAdminWhat it's for
Browse✅ sees every folderHome page — folders, recent documents, quick actions (§9).
DashboardQuotas, recent activity, folders shared with you (§14).
Trash✅ own only✅ own only✅ everyone'sRestore or permanently delete (§15).
UsersInvite, change role/status, delete accounts (§16).
Audit LogEvery sensitive action, platform-wide (§17).
Never "you're not allowed" — just "not found" Opening a folder or document you have no grant on (directly or inherited from a parent folder) returns a plain 404, in the web app and the API alike — the same response as one that doesn't exist at all, so a stranger can never confirm something even exists by probing for a 403.

6. Signing In

Via the Web App

  1. Open https://demo2.arsiindiainfo.com — you land on the sign-in page.
  2. Enter one of the demo emails (§4) and Passw0rd!, or your own account (§7).
  3. Tick the reCAPTCHA checkbox.
  4. Click Sign in. You land on Browse (§9).
Sign-in page
The sign-in page, with a link to create a new account (§7).
Why there's a reCAPTCHA checkbox POST /auth/login and POST /auth/register are the only endpoints anyone can call without already being logged in — the obvious targets for scripted/credential-stuffing traffic. Both require a Google reCAPTCHA v2 check, verified server-side, before the request is accepted.

Via the API

POST https://demo2.arsiindiainfo.com/api/v1/auth/login
Content-Type: application/json

{
  "email": "admin@meridian.test",
  "password": "Passw0rd!",
  "recaptchaToken": "03AGdBq27..."
}
{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOi...",
    "refreshToken": "9ba3b6cf3c...",
    "user": { "id": 1, "name": "Ava Admin", "email": "admin@meridian.test", "role": "ADMIN", "status": "ACTIVE" }
  }
}

Copy the accessToken and send it on every subsequent request: Authorization: Bearer eyJhbGciOi...

7. Creating Your Own Account

Anyone can self-register — a new account starts as a Manager with no folders of their own, so creating a root folder (§10) is also its first action.

Via the Web App

  1. Click Create one on the sign-in page.
  2. Fill in your name, email, and password, and complete the reCAPTCHA.
  3. Submit — a verification link is emailed to you. Signing in before clicking it returns 403 EMAIL_NOT_VERIFIED.
  4. Click the link (or open /verify-email/:token directly), then sign in (§6).
Create your account page
Creating a new account.

Via the API: POST/auth/register{ name, email, password, recaptchaToken }. POST/auth/verify-email/:token.

8. Your Session & Signing Out

Access tokens are short-lived. The web app quietly exchanges the refreshToken for a new pair whenever a request comes back 401 — you won't see a token expire while using the app.

Via the Web App: click your avatar (top right) → Sign out, or Change password to update your own credentials. Via the API: POST/auth/refresh · POST/auth/logout · PUT/users/me/password.

Avatar menu — Change password and Sign out
The avatar menu.
Change password dialog
Changing your password signs out every other session.

9. The Browse Page (Home)

Browse is the landing page after sign-in — a welcome banner, live stat cards, your folders as a colorful grid, a Recent Documents table, and a Quick Actions panel.

Browse home page — stat cards, folder grid, recent documents table, quick actions
Browse — the home page.

Via the API: GET/folders/children (no id segment = root) returns your accessible top-level folders; GET/dashboard (§14) backs the stat cards and Recent Documents table.

10. Folders

Via the Web App

  1. Click New folder from Browse or from inside any folder you can edit.
  2. Click a folder card to open it — Rename and Delete appear on hover; Share is always visible (§12).
  3. Deleting moves it (and everything inside it) to Trash (§15) — nothing is gone for good yet.
New folder dialog
Creating a folder.
Rename folder dialog
Renaming one.
Inside a folder — breadcrumb, subfolders, and documents with per-type icons
Inside a folder — breadcrumb navigation, subfolders, and documents.
Permission inheritance A grant on a folder applies to everything inside it, unless a subfolder or document has its own more specific grant — the closest explicit grant always wins over an inherited one.

Via the API

POST/folders{ name, parentFolderId? }. A duplicate name in the same parent returns 409 DUPLICATE_NAME; over the 20-folder quota (§14) returns 409 FOLDER_QUOTA_EXCEEDED. GET/folders/:id/children · PUT/folders/:id · DELETE/folders/:id.

11. Uploading & Viewing Documents

Via the Web App

  1. Inside a folder, click Upload or drag files onto the page.
  2. Each file shows its type icon while uploading; once processed, a real thumbnail replaces the icon for images and PDFs.
  3. Click a document to open its detail panel — Details and Preview tabs, plus Download, Share, Upload new version, and Delete.
Allowed file types & limits PDF, Word (.doc/.docx), Excel (.xls/.xlsx), PowerPoint (.ppt/.pptx), CSV, TXT, RTF, PNG, JPG, GIF, WebP, ZIP — anything that can carry executable/script content (HTML, SVG, JS) is deliberately excluded. 10MB per file, 100 files and 100MB total per user (§14) — a file over the limit returns 400 FILE_TOO_LARGE, an unsupported type returns 400 UNSUPPORTED_FILE_TYPE.

Via the API

Upload is a two-step, direct-to-S3 flow — the API server never sees the file bytes:

  1. POST/documents/uploads/initiate{ folderId, fileName, mimeType, sizeBytes } returns a presigned PUT URL.
  2. Upload the file straight to that URL, then POST/documents/uploads/complete{ folderId, s3Key, name, checksumSha256 } to finalize.

GET/documents/:id/download · GET/documents/:id/preview · GET/documents/:id/thumbnail — each returns a short-lived presigned URL, never the file itself. POST/documents/:id/versions/initiate/complete — upload a new version of an existing document.

12. Sharing — Documents and Folders

Both a folder and an individual document can be shared the same way: invite a teammate by email at Viewer/Editor/Owner, or — for documents only — generate a revocable, expiring public link that needs no account at all.

Via the Web App

  1. Click Share on any folder card or document row.
  2. Under Invite a person, start typing a name or email — matching teammates appear in a dropdown; click one to fill it in, pick a permission, and click Invite.
  3. Documents only: under External link, choose View or Download, an expiry (1 or 7 days), and an optional max-download cap, then click Generate link.
  4. Anyone already granted access is listed with a Revoke link next to their name.
Share dialog — invite-a-person autocomplete suggesting a teammate
The autocomplete suggests teammates as you type.
Share dialog for a document — existing grant, and a generated external link
A document's Share dialog, with a generated external link.
Share dialog for a folder — no external link section, since links are document-only
Sharing a folder instead — no External Link section, since public links stay document-only.
Only an Owner can manage grants Inviting or revoking access requires OWNER on that specific item — an Editor can generate external links but not manage who else has access. Revoking the last remaining Owner returns 409 LAST_OWNER instead of leaving the item ownerless.

Opening a public link with no account at all

A share link opens a standalone page — no app header, no sign-in — showing the file name and size, a Download (or, for View links, an inline preview) button. Revoking it from the Share dialog, or letting it expire or hit its download cap, immediately breaks the link (409 SHARE_LINK_REVOKED / SHARE_LINK_EXPIRED / SHARE_LINK_LIMIT_REACHED).

Via the API

POST/folders/:id/permissions / /documents/:id/permissions{ email, permission }. GET the same path lists current grants; DELETE .../permissions/:userId revokes one. POST/documents/:id/share-links{ permission, expiresInHours, maxDownloads? }. GET/s/:token is the public, unauthenticated resolve — no bearer token, ever.

GET/users/search?q= — the autocomplete's lookup, available to any signed-in user (id/name/email only, never role/status).

Via the Web App: type into the search box in the top bar and press Enter — results show every document you can access, across every folder, with its folder location and size.

Via the API: GET/documents?search=&page=1&limit=20.

14. The Dashboard & Your Quotas

Every quota is checked against your current (non-deleted) state, not a lifetime counter — deleting something frees its slot back up immediately.

LimitValue
Folders20 at a time
Files100 at a time
Per-file size10MB
Total storage100MB
Dashboard — quota progress bars, recently accessed documents, folders shared with you
The Dashboard — quota bars turn red near the limit.

Via the API: GET/dashboard returns recentDocuments, storageUsedBytes, sharedFolders, and quotas as one payload.

15. Trash — Restore or Delete Forever

Deleting a folder or document moves it to Trash — recoverable for 30 days (§18), after which an automatic job purges it for good.

Via the Web App

  1. Open Trash — each row shows how many days remain before automatic purge.
  2. Click Restore to bring it back, or Delete permanently to purge it immediately — this is irreversible, and a confirmation dialog says so.
Trash — deleted folders and documents with days-remaining and restore/purge actions
Trash.
Restoring a folder needs its parent restored first Restoring a folder whose own parent is still deleted returns 422 PARENT_FOLDER_NOT_FOUND — restore the parent first, then the child.

Via the API: GET/trash · POST/folders/:id/restore / /documents/:id/restore · DELETE/trash/folders/:id / /trash/documents/:id — permanent, requires it to already be in Trash (409 NOT_IN_TRASH otherwise).

16. Admin: User Management

Sign in as an admin account (§4) to manage the team. These endpoints return 403 FORBIDDEN_ROLE for anyone else.

  1. Open Users — click Invite (name, email, role) to add someone directly (no self-registration needed).
  2. Change a user's role from the dropdown, or click Disable/Enable to toggle their access.
  3. Click Delete to permanently remove an account — this fails with 409 USER_HAS_CONTENT if they still own folders or documents that exist.
Admin Users screen — invite, role, status, delete
Admin: User management.

Via the API: POST/users · GET/users · PUT/users/:id{ role?, status? } · DELETE/users/:id — blocked for your own account, and for one protected super-admin account.

17. Admin: Audit Log

Every sensitive action — a folder created, a permission granted, a user invited, a file permanently deleted — is written to an append-only trail, automatically pruned after 3 months (§18).

Admin Audit Log — action, entity, user, timestamp
Admin: Audit Log — click a row to expand its details.

Via the API: GET/audit-logs.

18. Storage Lifecycle & Automatic Cleanup

Two scheduled jobs run against this deployment without any user action:

1
Old file cleanup
Files older than 30 days: keep the latest 5 per document, delete the rest (S3 + DB) and notify the owner
·
2
Trash purge
Anything in Trash for 30+ days is permanently deleted
·
3
Audit log retention
Rows older than 3 months are pruned

None of this needs a click — it runs on a schedule server-side (php spark cleanup:old-files / cleanup:audit-logs).

19. Error Responses

HTTPCodeMeaning
400VALIDATION_ERRORThe request body failed validation.
400FILE_TOO_LARGEOver the 10MB per-file limit (§11).
400UNSUPPORTED_FILE_TYPENot one of the 15 allowed mime types (§11).
400INCORRECT_PASSWORDWrong current password on a change-password attempt.
400RECAPTCHA_FAILEDThe reCAPTCHA check didn't pass.
400INVALID_VERIFICATION_TOKENAn expired/invalid email-verification token (§7).
401UNAUTHORIZEDMissing/expired token or invalid credentials.
401INVALID_SIGNATUREAn internal HMAC-signed request's signature didn't match.
403FORBIDDEN_ROLEYour account's role can't perform this action.
403EMAIL_NOT_VERIFIEDSign in attempted before verifying the account (§7).
404FOLDER_NOT_FOUND / DOCUMENT_NOT_FOUND / DOCUMENT_VERSION_NOT_FOUND / USER_NOT_FOUND / SHARE_LINK_NOT_FOUND / PERMISSION_GRANT_NOT_FOUND / THUMBNAIL_NOT_READYDoesn't exist, isn't ready yet, or you have no grant on it (§5).
409DUPLICATE_NAMEA folder/document name that must be unique in its parent already exists.
409FOLDER_QUOTA_EXCEEDED / FILE_QUOTA_EXCEEDED / STORAGE_QUOTA_EXCEEDEDOver one of the four limits in §14.
409LAST_OWNERRevoking the last remaining Owner on an item (§12).
409NOT_IN_TRASHTrying to permanently delete something that isn't in Trash first.
409DOCUMENT_DELETEDActing on a document that's already been soft-deleted.
409USER_HAS_CONTENTDeleting a user who still owns folders/documents that exist (§16).
409SHARE_LINK_EXPIRED / SHARE_LINK_REVOKED / SHARE_LINK_LIMIT_REACHEDThe public link is no longer valid (§12).
422PARENT_FOLDER_NOT_FOUNDThe destination/parent folder doesn't exist or is deleted (§15).
422CYCLE_DETECTEDMoving a folder into its own descendant.
429RATE_LIMITEDToo many login attempts — slow down and retry.
500INTERNAL_ERRORAn unexpected server-side error.

20. Full Endpoint Reference

All paths are relative to https://demo2.arsiindiainfo.com/api/v1.

MethodPathAuthDescription
POST/auth/registerPublic + reCAPTCHASelf-register (§7)
POST/auth/verify-emailPublicActivate a registered account
POST/auth/loginPublic + reCAPTCHASign in (§6)
POST/auth/refreshPublicExchange a refresh token for a new pair
POST/auth/logoutBearerRevoke a refresh token
GET/users/meBearerYour own profile
PUT/users/me/passwordBearerChange your own password
GET/users/search?q=BearerAutocomplete lookup for sharing (§12)
GET/usersAdminList every user (§16)
POST/usersAdminInvite a user
PUT/users/:idAdminUpdate role/status
DELETE/users/:idAdminPermanently delete a user
POST/foldersBearerCreate a folder (§10)
GET/folders/:idBearerFolder detail + your effective permission
GET/folders/:id/childrenBearerList a folder's contents (or root, no id)
PUT/folders/:idBearerRename/move a folder
DELETE/folders/:idBearerSoft-delete (§15)
POST/folders/:id/restoreBearerRestore from Trash
POST/folders/:id/permissionsBearer (Owner)Grant access (§12)
GET/folders/:id/permissionsBearer (Owner)List grants
DELETE/folders/:id/permissions/:userIdBearer (Owner)Revoke a grant
GET/documentsBearerSearch across every accessible document (§13)
POST/documents/uploads/initiateBearerPresigned upload URL (§11)
POST/documents/uploads/completeBearerFinalize an upload
GET/documents/:idBearerDocument detail + your effective permission
PUT/documents/:idBearerRename/update metadata
DELETE/documents/:idBearerSoft-delete (§15)
POST/documents/:id/restoreBearerRestore from Trash
POST/documents/:id/versions/initiateBearerUpload a new version
POST/documents/:id/versions/completeBearerFinalize a new version
GET/documents/:id/versionsBearerVersion history
GET/documents/:id/downloadBearerPresigned download URL
GET/documents/:id/previewBearerPresigned inline-preview URL
GET/documents/:id/thumbnailBearerPresigned thumbnail URL
POST/documents/:id/permissionsBearer (Owner)Grant access (§12)
GET/documents/:id/permissionsBearer (Owner)List grants
DELETE/documents/:id/permissions/:userIdBearer (Owner)Revoke a grant
POST/documents/:id/share-linksBearer (Owner/Editor)Create an external link
GET/documents/:id/share-linksBearer (Owner/Editor)List links + download counts
DELETE/share-links/:idBearer (Owner/Editor)Revoke a link immediately
GET/s/:tokenPublicResolve a share link (§12)
GET/dashboardBearerQuotas, recent activity, shared folders (§14)
GET/trashBearerEverything in Trash (§15)
DELETE/trash/folders/:idBearerPermanently purge a folder
DELETE/trash/documents/:idBearerPermanently purge a document
GET/audit-logsAdminPlatform-wide audit trail (§17)

21. FAQ & Troubleshooting

The reCAPTCHA checkbox won't check, or my login is rejected

Make sure third-party content isn't blocked by a privacy extension — the widget loads a script from google.com. If the checkbox works but submission still fails, the token likely expired (about two minutes); the form resets it automatically — just complete it again.

I uploaded a file and it still shows a generic icon, not a thumbnail

Thumbnails are generated asynchronously after upload — give it a few seconds and refresh. Only images and PDFs get a real thumbnail; everything else always shows its type icon by design.

I deleted a folder — is everything inside it gone?

No — deleting a folder moves it and everything inside it to Trash (§15) together, recoverable as a whole for 30 days. Nothing is actually removed until you purge it, or the automatic 30-day job does (§18).

Why did my file disappear even though I never deleted it?

The 30-day old-file cleanup job (§18) keeps only the latest 5 versions of files older than 30 days and removes the rest — you'd have received a notification when it happened. The current version is never touched.

I opened a shared link and it says it's invalid — was it ever valid?

By design this platform doesn't distinguish "expired" from "revoked" from "never existed" in most contexts (§5's guardrail) — but share links are the one exception, returning a specific reason (SHARE_LINK_EXPIRED/REVOKED/LIMIT_REACHED) since there's no ownership-privacy concern on a link someone already had.

Where do I see the full request/response schema for every field?

The interactive Swagger UI at /api/docs documents every field, validation rule, and example — it's disabled on the public demo, so run the project locally (see the repo's README) to browse it.

Arsi India Info logo
Need more detail? This guide covers the day-to-day workflows. Schema, stored procedures, and security architecture are documented separately in the project's docs/ folder and its README.