# Product Requirements Document ## Product **Name:** S3 Mover **Document version:** 0.1 **Date:** 2026-03-26 **Status:** Draft ## Overview S3 Mover is a web application for securely managing files across one or more S3-compatible buckets. The system provides a React frontend and Go backend, with SQLite as the system of record for users, bucket access, invitations, audit logs, and authentication-related metadata. The existing proof of concept demonstrated that a Go backend can enumerate files and perform upload, download, and delete operations against S3-compatible object storage. This product extends that proof of concept into a production-oriented multi-user application with user management, per-user bucket credentials, invitation-based onboarding, mandatory 2FA, audit logging, and Docker deployment. ## Problem Statement The proof of concept is functionally viable, but it is not suitable for real users because: - There is no user management or role-based access control. - Storage credentials are configured globally instead of per user and per bucket. - There is no secure onboarding flow. - There is no multi-factor authentication. - There is no audit trail for file operations. - Sensitive bucket configuration is not yet modeled as protected server-side data. The product must evolve into a secure internal application that allows administrators to manage users and user-specific bucket credentials, while allowing standard users to operate only on the buckets assigned to them. ## Goals - Provide secure user authentication using email, password, and TOTP-based 2FA. - Support administrator-led invitation onboarding via Resend email. - Allow administrators to manage users and assign one or more bucket configurations to each user. - Keep all sensitive bucket credentials server-side only. - Provide file browsing and upload, download, and delete capabilities for the assigned bucket(s) of a logged-in user. - Record auditable logs of bucket operations. - Persist system data in SQLite. - Package the application for Docker deployment. ## Non-Goals - End-user self-registration. - SSO, SAML, or OAuth identity providers in the first release. - Bucket creation or infrastructure provisioning. - Advanced IAM policy editing or credential rotation workflows. - Object versioning, lifecycle management, or ACL management. - Bulk file operations beyond single upload, download, and delete. - Fine-grained per-prefix authorization within a bucket in the first release. ## Users and Roles ### Administrator The administrator manages the system and has access to all administrative functions. Capabilities: - Log in with email, password, and TOTP - View all registered users - View details for an individual user - Invite a new user by email - Delete a user account - Add one or more bucket credential sets to a user - Remove a bucket credential set from a user - View audit logs for all file operations ### Standard User The standard user interacts only with buckets assigned to their account. Capabilities: - Complete invitation onboarding - Set a strong password - Enroll a TOTP authenticator during first-time setup - Log in with email, password, and TOTP - View the list of assigned buckets in a left sidebar - Select a bucket and view its contents - Upload, download, and delete files within assigned buckets ## Key User Journeys ### 1. Administrator Invites a User 1. Administrator logs into the application. 2. Administrator navigates to the user management page. 3. Administrator creates a new user by entering at least an email address. 4. System creates a pending user record and a time-limited invitation token. 5. System sends an invitation email through Resend. 6. Email contains a secure link to the onboarding page. ### 2. User Accepts Invite and Creates Credentials 1. User clicks the invitation link. 2. System validates the invitation token. 3. User is prompted to set a strong password. 4. User is required to enroll a TOTP authenticator before activation completes. 5. User confirms setup by entering a valid TOTP code. 6. System activates the account and marks the invitation as consumed. ### 3. User Logs In 1. User enters email address and password. 2. System validates credentials. 3. User is prompted for a TOTP code. 4. System issues a JWT after successful second-factor verification. 5. User is redirected to the main application. ### 4. User Operates on a Bucket 1. User logs in successfully. 2. User sees a sidebar listing assigned buckets. 3. User selects a bucket. 4. System displays the bucket name and endpoint at the top of the page. 5. System shows a paginated file list with 15 items per page. 6. User uploads, downloads, or deletes files. 7. System records an audit log entry for each file operation. ### 5. Administrator Manages Bucket Credentials for a User 1. Administrator navigates to a user detail page. 2. Administrator adds a bucket credential set for that user. 3. Administrator enters: - AWS access key ID - AWS secret access key - AWS region - bucket name - S3-compatible endpoint 4. System stores those credentials securely in SQLite. 5. User gains access to that bucket after next authorized fetch or session refresh. 6. Administrator may remove a bucket configuration from the user later. ## Functional Requirements ## FR-1 Authentication - The system shall support login using email address and password. - The system shall require TOTP as a second factor for all users. - The system shall issue JWTs for authenticated API access. - The system shall reject access to protected routes without a valid JWT. - The system shall support logout by invalidating the client session. ## FR-2 Invitation and Onboarding - Only an administrator may create a new user. - Creating a user shall generate an invite email sent through Resend. - The invite shall contain a secure, time-limited, single-use token. - The invite flow shall require the user to set a strong password. - The invite flow shall require TOTP setup before account activation. - An invited user shall not be able to log in until onboarding is complete. ## FR-3 User Management - The administrator shall have a page listing all users. - The user list shall include at minimum email address, status, role, created date, and last login date if available. - The administrator shall be able to click into a user detail page. - The administrator shall be able to delete a user account. - Deleting a user shall revoke future access immediately. ## FR-4 Bucket Assignment - A user shall be assigned at least one bucket credential set to access storage. - A user may have multiple bucket credential sets. - Each bucket credential set shall be unique to the user and shall not be shared by design. - The administrator shall be able to create, view metadata for, and remove bucket assignments for a user. - Sensitive values such as access keys and secrets shall not be shown back to the browser after creation, except where explicitly required for a masked administrative UX. ## FR-5 Bucket Browsing and File Operations - A logged-in user shall see assigned buckets in a left sidebar. - Selecting a bucket shall show: - bucket name - endpoint - paginated file listing - Pagination shall be fixed at 15 items per page. - The system shall support upload, download, and delete operations for files in the selected bucket. - The system shall support S3-compatible providers, not just AWS S3. ## FR-6 Audit Logging - The system shall log all user file operations. - Each log entry shall include at minimum: - timestamp - user ID - user email - bucket identifier - file key - operation type - The operation type shall support at minimum: - upload - download - delete - Only administrators shall be able to view logs. ## FR-7 Administrative Access Control - Only administrators shall be able to: - invite users - view all users - view user details - manage user bucket assignments - delete users - view audit logs ## FR-8 Deployment and Runtime - The application shall run in Docker. - The backend shall be implemented in Go. - The frontend shall be implemented in React. - SQLite shall be the primary application database. ## Security Requirements - Sensitive bucket credentials shall never be sent to the browser. - Sensitive bucket credentials shall never be included in JWT payloads. - JWTs shall be signed server-side with a configurable secret or private key. - Passwords shall be stored only as strong salted hashes. - TOTP secrets shall be stored securely server-side. - Invite tokens shall be stored hashed or otherwise protected server-side and shall expire. - The application shall enforce HTTPS in deployed environments. - The application shall implement CSRF protections if JWTs are stored in cookies. - The application shall implement rate limiting or equivalent brute-force protection for authentication endpoints. - All sensitive configuration shall be provided through environment variables or secret injection at runtime. - Administrative and user actions shall be authorized server-side for every request. ## UX Requirements ### Authentication - The application shall provide: - login page - TOTP challenge page - invitation acceptance page - password setup form - TOTP enrollment page with QR code and manual key fallback ### Main User Application - The main authenticated layout shall include: - left sidebar for bucket selection - top area showing selected bucket name and endpoint - file listing view - pagination controls - upload action - download action - delete action ### Administration - The administrator area shall include: - user list page - user detail page - add bucket assignment flow - audit log page ## Data Model Requirements The following logical entities are required. ### users - id - email - role - status - password_hash - totp_secret - totp_enabled - invited_at - activated_at - last_login_at - created_at - updated_at ### invitations - id - user_id - email - token_hash - expires_at - consumed_at - created_by_user_id - created_at ### user_bucket_credentials - id - user_id - display_name - aws_access_key_id - aws_secret_access_key - aws_region - s3_bucket - aws_endpoint_url - use_path_style - created_at - updated_at ### audit_logs - id - user_id - user_email - bucket_credential_id - bucket_name - endpoint - file_key - operation - created_at - request_ip - user_agent ### sessions or token metadata Implementation may use stateless JWTs only, but the design should allow optional storage for token revocation, refresh sessions, or login tracking if needed. ## Recommended Status Values ### User status - invited - active - disabled ### Role - admin - user ### Audit operation - upload - download - delete ## API Requirements The final API shape may change, but the following resources are expected. ### Authentication - `POST /api/auth/login` - `POST /api/auth/totp/verify` - `POST /api/auth/logout` - `GET /api/auth/me` ### Invitations - `POST /api/admin/users/invite` - `GET /api/invitations/:token` - `POST /api/invitations/:token/accept` ### Administration - `GET /api/admin/users` - `GET /api/admin/users/:userId` - `DELETE /api/admin/users/:userId` - `POST /api/admin/users/:userId/buckets` - `DELETE /api/admin/users/:userId/buckets/:bucketCredentialId` - `GET /api/admin/audit-logs` ### User bucket access - `GET /api/me/buckets` - `GET /api/me/buckets/:bucketCredentialId/files?page=1&pageSize=15` - `POST /api/me/buckets/:bucketCredentialId/files` - `GET /api/me/buckets/:bucketCredentialId/files/:key` - `DELETE /api/me/buckets/:bucketCredentialId/files/:key` ## Business Rules - Every non-admin user must authenticate with password plus TOTP. - An invitation may only be used once. - A bucket credential set belongs to exactly one user. - A user may have zero bucket assignments during setup or after administrative changes, but a user must have at least one assignment to perform storage operations. - The server shall resolve storage access from the selected bucket credential ID and not from any client-supplied raw credential values. - The browser may know a bucket display name, bucket name, and endpoint, but not secret credentials. ## Technical Requirements ### Backend - Go HTTP API - SQLite persistence - JWT authentication middleware - Password hashing using a modern algorithm such as Argon2id or bcrypt - TOTP support using a standard authenticator-compatible implementation - Resend integration for invitation emails - S3-compatible client abstraction for storage operations - Audit log persistence for all storage mutations and downloads ### Frontend - React application - Authenticated routing - Admin-only views and user views - Sidebar bucket navigation - Paginated bucket file list with page size fixed to 15 - Forms for onboarding, login, TOTP verification, user management, and bucket assignment ### Infrastructure and Deployment - Single Docker image or Docker Compose-based local runtime - Persistent storage volume for SQLite database - Environment-based configuration for JWT secret, Resend API key, and bootstrap admin settings ## Reporting and Logging Requirements - Application logs shall capture authentication failures, invitation events, administrative changes, and storage operation failures. - Audit logs shall be queryable by administrators. - Audit log views should support filtering by: - date range - user - bucket - operation ## Constraints - SQLite is the required datastore for the initial production-ready version. - The frontend must not directly communicate with S3-compatible storage using raw bucket credentials. - All storage operations must be proxied through the Go backend. - Sensitive settings must remain server-side. ## Assumptions - The first release supports one administrator bootstrap path via environment configuration, migration seed, or initial setup command. - Invitation emails will be transactional emails sent through Resend. - TOTP apps such as 1Password, Google Authenticator, or Authy are acceptable authenticators. - The application is intended for trusted organizational users rather than open public sign-up. ## Open Questions - How should the first administrator account be bootstrapped? - Should administrators also be able to perform bucket operations, or only manage users and logs? - Should deleted users be hard-deleted or soft-deleted for audit retention? - Should bucket secrets be encrypted at rest in SQLite using an application-level encryption key? - Should JWTs be short-lived access tokens only, or should the system also support refresh tokens? - What are the password strength rules beyond “strong password”? - What is the invite expiration window? - Should audit logs include failed file operations in addition to successful ones? - Is account disablement required in addition to deletion? - Are per-user bucket display names needed in the UI, or is raw bucket name sufficient? ## Success Criteria - Administrators can invite, onboard, and manage users without manual database changes. - Standard users can access only their assigned buckets. - Bucket credentials never appear in browser network payloads or rendered UI. - Users must complete TOTP enrollment before account activation. - All file uploads, downloads, and deletes are auditable by administrators. - The application runs successfully in Docker with SQLite persistence. ## Proposed Delivery Phases ### Phase 1: Identity and Administration Foundation - SQLite schema and migrations - bootstrap administrator - login, password hashing, JWT issuance - TOTP enrollment and verification - invite flow with Resend - admin user list and user detail pages ### Phase 2: Bucket Assignment and Secure Access - per-user bucket credential storage - admin create and remove bucket credentials - authenticated bucket list API - user sidebar and selected-bucket view - secure server-side storage operations using assigned credentials ### Phase 3: Auditability and Production Hardening - audit log persistence and admin log viewer - Docker packaging - operational logging and error handling - rate limiting and security hardening - UX polish and edge-case handling