Repository Structure
A map of the codebase as it exists today, not as originally planned - every path below was checked against the actual filesystem.
Root Directory
opndrive/
├── docs/ # This documentation site (Nextra) - content/ is the source of truth
├── frontend/ # Next.js application
├── s3-api/ # Workspace package: @opndrive/s3-api
├── CONTRIBUTING.md # Short contributor entry point
├── CODE_OF_CONDUCT.md
├── CHANGELOG.md # Frontend app changes (s3-api has its own)
├── SECURITY.md # How to report a vulnerability privately
├── LICENSE # AGPL-3.0
├── README.md
├── .github/ # CI/CodeQL workflows, Dependabot, issue + PR templates
├── .husky/ # Git hooks (pre-commit runs lint-staged)
├── Dockerfile # Multi-stage frontend image - build from the root
├── .dockerignore
├── .nvmrc # Pinned Node version (22) - CI reads this too
├── .prettierignore
├── eslint.config.mjs # Shared lint config for both packages
├── package.json # Root scripts and workspace helper commands
├── pnpm-lock.yaml # The only lockfile - packages don't have their own
├── pnpm-workspace.yaml
└── prettier.config.jsThere used to be a separate docs/ folder at the root, copied verbatim into
docs/content/. It was removed - Nextra has no supported way to read content
from outside its own app directory, so a copy meant two places that could
silently drift out of sync. docs/content/ is the only place these files live
now; it’s still plain Markdown/MDX, so it reads fine directly on GitHub too.
The root pnpm-workspace.yaml links frontend/, s3-api/, and docs/. Run
pnpm install once from the repository root to install all workspaces and link
the frontend to the local @opndrive/s3-api package.
Frontend (/frontend)
frontend/
├── public/ # Static assets
├── src/
│ ├── app/ # Next.js App Router
│ ├── features/ # Feature-based modules
│ ├── shared/ # Reusable components and utilities
│ ├── components/ # Non-feature-specific components (file preview, etc.)
│ ├── context/ # React Context providers
│ ├── hooks/ # Cross-feature custom hooks
│ ├── lib/ # Utilities, config helpers
│ ├── config/ # Feature flags and app config
│ ├── providers/ # App-level providers
│ ├── services/ # Wrappers around @opndrive/s3-api
│ ├── types/ # Shared TypeScript types
│ └── assets/ # Local static assets
├── components.json # shadcn/ui config
├── next.config.ts
├── package.json
├── tailwind.config.ts
└── tsconfig.jsonApp Router (src/app)
app/
├── layout.tsx # Root layout
├── page.tsx # Landing page
├── not-found.tsx
├── robots.ts / sitemap.ts # SEO
├── connect/page.tsx # AWS credential setup wizard
├── blog/ # page.tsx, [slug]/page.tsx, layout.tsx
├── api/revalidate/route.ts # On-demand revalidation endpoint
└── dashboard/
├── layout.tsx / page.tsx # Dashboard shell + home
├── browse/page.tsx # File and folder browsing
├── search/page.tsx
├── settings/ # layout.tsx, page.tsx
└── preview/ # layout.tsx, [etag]/page.tsx - route-based file previewThe blog and revalidate route are behind the NEXT_PUBLIC_ENABLE_BLOG flag (see
Environment Variables) and are a
separate marketing surface from the drive product itself - if you’re working on
the dashboard, you can generally ignore them.
Features (src/features)
features/
├── dashboard/ # Main file browser: components/, hooks/, services/, stores/, types/
├── upload/ # Upload flow: components/, hooks/, stores/
├── file-management/ # Rename/delete helpers
├── folder-navigation/ # Breadcrumb + prefix navigation logic
├── settings/ # App settings and preferences
└── landing-page/ # Components specific to the marketing home pageEach feature owns its components/, and larger ones add hooks/, stores/
(Zustand), or services/ as needed - there’s no fixed template every feature
must follow, but features/dashboard is the most complete example to copy from.
Shared (src/shared)
shared/
├── components/
│ ├── ui/ # Primitives: button, input, dialog, ... (shadcn/ui based)
│ ├── icons/ # File and folder type icons
│ └── layout/ # Cross-page layout pieces (loading bar, etc.)S3 API (/s3-api)
s3-api/
├── src/
│ ├── core/
│ │ ├── index.ts # Abstract interface
│ │ ├── index.test.ts # Client construction, accessors, debugLog
│ │ └── types.ts
│ ├── utils/ # Each of these has a collocated *.test.ts
│ │ ├── uploadManager.ts # Multipart upload orchestration
│ │ ├── signedUrlUploadManager.ts # Signed-URL upload orchestration
│ │ ├── signedUrlUploader.ts
│ │ ├── multipartUploader.ts
│ │ └── concurrency.ts
│ ├── tests/ # contentDisposition unit tests + credential-gated integration suite
│ ├── index.ts # Public exports
│ ├── index.listing.test.ts # Listing + metadata coverage
│ ├── index.objects.test.ts # Single-object operation coverage
│ ├── index.rename.test.ts # move/rename file + folder coverage
│ ├── index.multipart.test.ts # uploadMultipartParallely coverage
│ └── vitest.d.ts # Types for the aws-sdk-client-mock matchers
├── CHANGELOG.MD
├── package.json # Workspace package, publishable as @opndrive/s3-api
├── tsconfig.json # Type-checking (includes test files)
├── tsconfig.build.json # Build only (excludes test files from dist/)
├── vitest.config.ts
└── vitest.setup.ts # Registers the AWS mock matchersUnit tests are collocated with the code they cover; src/tests/ predates that
convention and still holds the contentDisposition unit tests alongside the
credential-gated integration suite. See Testing.
See S3 API Layer for what each of these actually does.
Import Aliasing
// Good
import { Button } from '@/shared/components/ui/button';
import { FileItem } from '@/features/dashboard/types/file';
import { useDriveStore } from '@/context/data-context';
// Avoid
import { Button } from '../../../shared/components/ui/button';File Naming
kebab-case for files and folders throughout both packages.
Where to Start Reading
src/app- see how pages map to routes.src/features/dashboard- the most complete example of the feature pattern.src/shared/components/ui- the primitives everything else is built from.- Frontend Architecture for how these fit together.