diff --git a/.devcontainer/on-create.sh b/.devcontainer/on-create.sh index a66491ef7..fbd5351f2 100755 --- a/.devcontainer/on-create.sh +++ b/.devcontainer/on-create.sh @@ -9,10 +9,5 @@ npm install # Copy the env file cp .env.example .env -# Source the env file, export the variables -set -a -source .env -set +a - # Run the migrations -npm run -w @documenso/prisma prisma:migrate-dev +npm run prisma:migrate-dev diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 000000000..d12bdad59 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,50 @@ +--- +name: Bug Report +about: Create a bug report to help us improve +--- + + + +## Issue Description + + + +## Steps to Reproduce + + + + +1. Step 1 +2. Step 2 +3. ... + +## Expected Behavior + + + +## Current Behavior + + + +## Screenshots (optional) + + + +## Environment + + + +- OS: [e.g., Windows 10] +- Browser: [e.g., Chrome, Firefox] +- Version: [e.g., 2.0.1] + +## Checklist + + + + +- [ ] I have searched the existing issues to make sure this is not a duplicate. +- [ ] I have provided steps to reproduce the issue. +- [ ] I have included relevant environment information. +- [ ] I have included any relevant screenshots. +- [ ] I understand that this is a voluntary contribution and that there is no guarantee of resolution. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 000000000..a850a7a9a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,41 @@ +--- +name: Feature Request +about: Suggest a new idea or enhancement for this project +--- + + + +## Feature Description + + + + +## Use Case + + + + +## Proposed Solution + + + + +## Alternatives (optional) + + + + +## Additional Context + + + +## Checklist + + + + +- [ ] I have searched the existing feature requests to make sure this is not a duplicate. +- [ ] I have provided a detailed description of the requested feature. +- [ ] I have explained the use case or scenario for this feature. +- [ ] I have included any relevant technical details or design suggestions. +- [ ] I understand that this is a suggestion and that there is no guarantee of implementation. diff --git a/.github/ISSUE_TEMPLATE/improvement.md b/.github/ISSUE_TEMPLATE/improvement.md new file mode 100644 index 000000000..709d3441f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/improvement.md @@ -0,0 +1,41 @@ +--- +name: General Improvement +about: Suggest a minor enhancement or improvement for this project +--- + + + +## Improvement Description + + + + +## Rationale + + + + +## Proposed Solution + + + + +## Alternatives (optional) + + + + +## Additional Context + + + +## Checklist + + + + +- [ ] I have searched the existing issues and improvement suggestions to avoid duplication. +- [ ] I have provided a clear description of the improvement being suggested. +- [ ] I have explained the rationale behind this improvement. +- [ ] I have included any relevant technical details or design suggestions. +- [ ] I understand that this is a suggestion and that there is no guarantee of implementation. diff --git a/.github/PULL_REQUEST_TEMPLATE/generic.md b/.github/PULL_REQUEST_TEMPLATE/generic.md new file mode 100644 index 000000000..70b668b5c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/generic.md @@ -0,0 +1,49 @@ +--- +name: Pull Request +about: Submit changes to the project for review and inclusion +--- + +## Description + + + + +## Related Issue + + + + +## Changes Made + + + + +- Change 1 +- Change 2 +- ... + +## Testing Performed + + + + +- Tested feature X in scenario Y. +- Ran unit tests for component Z. +- Tested on browsers A, B, and C. +- ... + +## Checklist + + + + +- [ ] I have tested these changes locally and they work as expected. +- [ ] I have added/updated tests that prove the effectiveness of these changes. +- [ ] I have updated the documentation to reflect these changes, if applicable. +- [ ] I have followed the project's coding style guidelines. +- [ ] I have addressed the code review feedback from the previous submission, if applicable. + +## Additional Notes + + + diff --git a/.github/PULL_REQUEST_TEMPLATE/test-addition.md b/.github/PULL_REQUEST_TEMPLATE/test-addition.md new file mode 100644 index 000000000..f93c81493 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/test-addition.md @@ -0,0 +1,40 @@ +--- +name: Test Addition +about: Submit a new test, either unit or end-to-end (E2E), for review and inclusion +--- + +## Description + + + + +## Related Issue + + + + +## Test Details + + + + +- Test Name: Name of the test +- Type: [Unit / E2E] +- Description: Brief description of what the test checks +- Inputs: What inputs the test uses (if applicable) +- Expected Output: What output or behavior the test expects + +## Checklist + + + + +- [ ] I have written the new test and ensured it works as intended. +- [ ] I have added necessary documentation to explain the purpose of the test. +- [ ] I have followed the project's testing guidelines and coding style. +- [ ] I have addressed any review feedback from previous submissions, if applicable. + +## Additional Notes + + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 74fcb319b..1269fd6c5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,7 +9,7 @@ updates: labels: - "ci dependencies" - "ci" - open-pull-requests-limit: 2 + open-pull-requests-limit: 0 - package-ecosystem: "npm" directory: "/apps/marketing" @@ -19,7 +19,7 @@ updates: labels: - "npm dependencies" - "frontend" - open-pull-requests-limit: 2 + open-pull-requests-limit: 0 - package-ecosystem: "npm" directory: "/apps/web" @@ -29,4 +29,4 @@ updates: labels: - "npm dependencies" - "frontend" - open-pull-requests-limit: 2 + open-pull-requests-limit: 0 diff --git a/README.md b/README.md index 2795d206d..f488b4a63 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ git clone https://github.com/documenso/documenso - NEXT_PRIVATE_SMTP_FROM_NAME - NEXT_PRIVATE_SMTP_FROM_ADDRESS -5. Create the database schema by running `npm run prisma:migrate-dev -w @documenso/prisma` +5. Create the database schema by running `npm run prisma:migrate-dev` 6. Run `npm run dev` root directory to start @@ -254,6 +254,22 @@ containers: - '::' ``` +### I can't see environment variables in my package scripts + +Wrap your package script with the `with:env` script like such: + +``` +npm run with:env -- npm run myscript +``` + +The same can be done when using `npx` for one of bin scripts: + +``` +npm run with:env -- npx myscript +``` + +This will load environment variables from your `.env` and `.env.local` files. + ## Repo Activity ![Repository Activity](https://repobeats.axiom.co/api/embed/622a2e9aa709696f7226304b5b7178a5741b3868.svg) diff --git a/apps/marketing/src/components/(marketing)/widget.tsx b/apps/marketing/src/components/(marketing)/widget.tsx index d81888463..d53f349e6 100644 --- a/apps/marketing/src/components/(marketing)/widget.tsx +++ b/apps/marketing/src/components/(marketing)/widget.tsx @@ -377,7 +377,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => { - + Add your signature diff --git a/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx b/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx index 666930b65..2fb06833b 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx @@ -1,5 +1,7 @@ 'use client'; +import { useState } from 'react'; + import Link from 'next/link'; import { @@ -32,6 +34,8 @@ import { useToast } from '@documenso/ui/primitives/use-toast'; import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard'; +import { DeleteDraftDocumentDialog } from './delete-draft-document-dialog'; + export type DataTableActionDropdownProps = { row: Document & { User: Pick; @@ -44,6 +48,8 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) = const { toast } = useToast(); const [, copyToClipboard] = useCopyToClipboard(); + const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false); + if (!session) { return null; } @@ -59,6 +65,7 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) = // const isPending = row.status === DocumentStatus.PENDING; const isComplete = row.status === DocumentStatus.COMPLETED; // const isSigned = recipient?.signingStatus === SigningStatus.SIGNED; + const isDocumentDeletable = isOwner && row.status === DocumentStatus.DRAFT; const onShareClick = async () => { const { slug } = await createOrGetShareLink({ @@ -147,7 +154,7 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) = Void - + setDeleteDialogOpen(true)} disabled={!isDocumentDeletable}> Delete @@ -168,6 +175,14 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) = Share + + {isDocumentDeletable && ( + + )} ); }; diff --git a/apps/web/src/app/(dashboard)/documents/delete-draft-document-dialog.tsx b/apps/web/src/app/(dashboard)/documents/delete-draft-document-dialog.tsx new file mode 100644 index 000000000..1a458a13d --- /dev/null +++ b/apps/web/src/app/(dashboard)/documents/delete-draft-document-dialog.tsx @@ -0,0 +1,89 @@ +import { useRouter } from 'next/navigation'; + +import { trpc as trpcReact } from '@documenso/trpc/react'; +import { Button } from '@documenso/ui/primitives/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@documenso/ui/primitives/dialog'; +import { useToast } from '@documenso/ui/primitives/use-toast'; + +type DeleteDraftDocumentDialogProps = { + id: number; + open: boolean; + onOpenChange: (_open: boolean) => void; +}; + +export const DeleteDraftDocumentDialog = ({ + id, + open, + onOpenChange, +}: DeleteDraftDocumentDialogProps) => { + const router = useRouter(); + + const { toast } = useToast(); + + const { mutateAsync: deleteDocument, isLoading } = + trpcReact.document.deleteDraftDocument.useMutation({ + onSuccess: () => { + router.refresh(); + + toast({ + title: 'Document deleted', + description: 'Your document has been successfully deleted.', + duration: 5000, + }); + + onOpenChange(false); + }, + }); + + const onDraftDelete = async () => { + try { + await deleteDocument({ id }); + } catch { + toast({ + title: 'Something went wrong', + description: 'This document could not be deleted at this time. Please try again.', + variant: 'destructive', + duration: 7500, + }); + } + }; + + return ( + !isLoading && onOpenChange(value)}> + + + Do you want to delete this document? + + + Please note that this action is irreversible. Once confirmed, your document will be + permanently deleted. + + + + +
+ + + +
+
+
+
+ ); +}; diff --git a/apps/web/src/app/(dashboard)/documents/page.tsx b/apps/web/src/app/(dashboard)/documents/page.tsx index d200fe262..d8a5a5bd8 100644 --- a/apps/web/src/app/(dashboard)/documents/page.tsx +++ b/apps/web/src/app/(dashboard)/documents/page.tsx @@ -66,7 +66,7 @@ export default async function DocumentsPage({ searchParams = {} }: DocumentsPage

Documents

-
+
{[ diff --git a/package-lock.json b/package-lock.json index 09985288c..4bbe127c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,8 @@ "devDependencies": { "@commitlint/cli": "^17.7.1", "@commitlint/config-conventional": "^17.7.0", - "dotenv": "^16.0.3", - "dotenv-cli": "^7.2.1", + "dotenv": "^16.3.1", + "dotenv-cli": "^7.3.0", "eslint": "^8.40.0", "eslint-config-custom": "*", "husky": "^8.0.0", @@ -9157,7 +9157,6 @@ "version": "16.3.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "dev": true, "engines": { "node": ">=12" }, @@ -9166,13 +9165,12 @@ } }, "node_modules/dotenv-cli": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.2.1.tgz", - "integrity": "sha512-ODHbGTskqRtXAzZapDPvgNuDVQApu4oKX8lZW7Y0+9hKA6le1ZJlyRS687oU9FXjOVEDU/VFV6zI125HzhM1UQ==", - "dev": true, + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.3.0.tgz", + "integrity": "sha512-314CA4TyK34YEJ6ntBf80eUY+t1XaFLyem1k9P0sX1gn30qThZ5qZr/ZwE318gEnzyYP9yj9HJk6SqwE0upkfw==", "dependencies": { "cross-spawn": "^7.0.3", - "dotenv": "^16.0.0", + "dotenv": "^16.3.0", "dotenv-expand": "^10.0.0", "minimist": "^1.2.6" }, @@ -9184,7 +9182,6 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, "engines": { "node": ">=12" } @@ -20207,6 +20204,8 @@ "license": "MIT", "dependencies": { "@prisma/client": "5.3.1", + "dotenv": "^16.3.1", + "dotenv-cli": "^7.3.0", "prisma": "5.3.1" }, "devDependencies": { diff --git a/package.json b/package.json index d072aa76d..787f7d7f9 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "private": true, "scripts": { "build": "turbo run build", + "build:web": "turbo run build --filter=@documenso/web", "dev": "turbo run dev --filter=@documenso/web --filter=@documenso/marketing", "start": "cd apps && cd web && next start", "lint": "turbo run lint", @@ -10,10 +11,13 @@ "commitlint": "commitlint --edit", "clean": "turbo run clean && rimraf node_modules", "d": "npm run dx && npm run dev", - "dx": "npm i && npm run dx:up && npm run prisma:migrate-dev -w @documenso/prisma", + "dx": "npm i && npm run dx:up && npm run prisma:migrate-dev", "dx:up": "docker compose -f docker/compose-services.yml up -d", "dx:down": "docker compose -f docker/compose-services.yml down", - "ci": "turbo run build test:e2e" + "ci": "turbo run build test:e2e", + "prisma:migrate-dev": "npm run with:env -- npm run prisma:migrate-dev -w @documenso/prisma", + "prisma:migrate-deploy": "npm run with:env -- npm run prisma:migrate-deploy -w @documenso/prisma", + "with:env": "dotenv -e .env -e .env.local --" }, "engines": { "npm": ">=8.6.0", @@ -22,8 +26,8 @@ "devDependencies": { "@commitlint/cli": "^17.7.1", "@commitlint/config-conventional": "^17.7.0", - "dotenv": "^16.0.3", - "dotenv-cli": "^7.2.1", + "dotenv": "^16.3.1", + "dotenv-cli": "^7.3.0", "eslint": "^8.40.0", "eslint-config-custom": "*", "husky": "^8.0.0", diff --git a/packages/lib/server-only/document/delete-draft-document.ts b/packages/lib/server-only/document/delete-draft-document.ts new file mode 100644 index 000000000..6b0bc3511 --- /dev/null +++ b/packages/lib/server-only/document/delete-draft-document.ts @@ -0,0 +1,13 @@ +'use server'; + +import { prisma } from '@documenso/prisma'; +import { DocumentStatus } from '@documenso/prisma/client'; + +export type DeleteDraftDocumentOptions = { + id: number; + userId: number; +}; + +export const deleteDraftDocument = async ({ id, userId }: DeleteDraftDocumentOptions) => { + return await prisma.document.delete({ where: { id, userId, status: DocumentStatus.DRAFT } }); +}; diff --git a/packages/prisma/package.json b/packages/prisma/package.json index 1b12a18a4..efd494ed6 100644 --- a/packages/prisma/package.json +++ b/packages/prisma/package.json @@ -18,6 +18,8 @@ }, "dependencies": { "@prisma/client": "5.3.1", + "dotenv": "^16.3.1", + "dotenv-cli": "^7.3.0", "prisma": "5.3.1" }, "devDependencies": { diff --git a/packages/trpc/server/auth-router/router.ts b/packages/trpc/server/auth-router/router.ts index ecb01cca3..f66f44325 100644 --- a/packages/trpc/server/auth-router/router.ts +++ b/packages/trpc/server/auth-router/router.ts @@ -12,12 +12,16 @@ export const authRouter = router({ return await createUser({ name, email, password, signature }); } catch (err) { - console.error(err); + let message = + 'We were unable to create your account. Please review the information you provided and try again.'; + + if (err instanceof Error && err.message === 'User already exists') { + message = 'User with this email already exists. Please use a different email address.'; + } throw new TRPCError({ code: 'BAD_REQUEST', - message: - 'We were unable to create your account. Please review the information you provided and try again.', + message, }); } }), diff --git a/packages/trpc/server/document-router/router.ts b/packages/trpc/server/document-router/router.ts index e436bb391..6d19afc0b 100644 --- a/packages/trpc/server/document-router/router.ts +++ b/packages/trpc/server/document-router/router.ts @@ -1,6 +1,7 @@ import { TRPCError } from '@trpc/server'; import { createDocument } from '@documenso/lib/server-only/document/create-document'; +import { deleteDraftDocument } from '@documenso/lib/server-only/document/delete-draft-document'; import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id'; import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token'; import { sendDocument } from '@documenso/lib/server-only/document/send-document'; @@ -10,6 +11,7 @@ import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/s import { authenticatedProcedure, procedure, router } from '../trpc'; import { ZCreateDocumentMutationSchema, + ZDeleteDraftDocumentMutationSchema, ZGetDocumentByIdQuerySchema, ZGetDocumentByTokenQuerySchema, ZSendDocumentMutationSchema, @@ -76,6 +78,25 @@ export const documentRouter = router({ } }), + deleteDraftDocument: authenticatedProcedure + .input(ZDeleteDraftDocumentMutationSchema) + .mutation(async ({ input, ctx }) => { + try { + const { id } = input; + + const userId = ctx.user.id; + + return await deleteDraftDocument({ id, userId }); + } catch (err) { + console.error(err); + + throw new TRPCError({ + code: 'BAD_REQUEST', + message: 'We were unable to delete this document. Please try again later.', + }); + } + }), + setRecipientsForDocument: authenticatedProcedure .input(ZSetRecipientsForDocumentMutationSchema) .mutation(async ({ input, ctx }) => { diff --git a/packages/trpc/server/document-router/schema.ts b/packages/trpc/server/document-router/schema.ts index c95417306..e5b27c0ea 100644 --- a/packages/trpc/server/document-router/schema.ts +++ b/packages/trpc/server/document-router/schema.ts @@ -61,3 +61,9 @@ export const ZSendDocumentMutationSchema = z.object({ }); export type TSendDocumentMutationSchema = z.infer; + +export const ZDeleteDraftDocumentMutationSchema = z.object({ + id: z.number().min(1), +}); + +export type TDeleteDraftDocumentMutationSchema = z.infer; diff --git a/packages/trpc/server/router.ts b/packages/trpc/server/router.ts index 6f9fc7660..b4c65b1d4 100644 --- a/packages/trpc/server/router.ts +++ b/packages/trpc/server/router.ts @@ -6,7 +6,9 @@ import { shareLinkRouter } from './share-link-router/router'; import { procedure, router } from './trpc'; export const appRouter = router({ - hello: procedure.query(() => 'Hello, world!'), + health: procedure.query(() => { + return { status: 'ok' }; + }), auth: authRouter, profile: profileRouter, document: documentRouter, diff --git a/packages/ui/primitives/dialog.tsx b/packages/ui/primitives/dialog.tsx index 8a0d8b21e..a67e35b03 100644 --- a/packages/ui/primitives/dialog.tsx +++ b/packages/ui/primitives/dialog.tsx @@ -16,12 +16,13 @@ const DialogPortal = ({ children, position = 'start', ...props -}: DialogPrimitive.DialogPortalProps & { position?: 'start' | 'end' }) => ( +}: DialogPrimitive.DialogPortalProps & { position?: 'start' | 'end' | 'center' }) => (
{children} @@ -49,7 +50,9 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; const DialogContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef & { position?: 'start' | 'end' } + React.ComponentPropsWithoutRef & { + position?: 'start' | 'end' | 'center'; + } >(({ className, children, position = 'start', ...props }, ref) => ( diff --git a/render.yaml b/render.yaml new file mode 100644 index 000000000..eb213c32c --- /dev/null +++ b/render.yaml @@ -0,0 +1,103 @@ +services: + - type: web + name: documenso-app + env: node + plan: free + buildCommand: npm i && npm run build:web + startCommand: npx prisma migrate deploy --schema packages/prisma/schema.prisma && npm run start + healthCheckPath: /api/trpc/health + + envVars: + # Node Version + - key: NODE_VERSION + value: 18.17.0 + + - key: PORT + value: 10000 + + # Auth + - key: NEXTAUTH_URL + fromService: + name: documenso-app + type: web + envVarKey: RENDER_EXTERNAL_URL + - key: NEXTAUTH_SECRET + generateValue: true + + # Database + - key: NEXT_PRIVATE_DATABASE_URL + fromDatabase: + name: documenso-db + property: connectionString + + - key: NEXT_PRIVATE_DIRECT_DATABASE_URL + fromDatabase: + name: documenso-db + property: connectionString + + # URLs + - key: NEXT_PUBLIC_WEBAPP_URL + fromService: + name: documenso-app + type: web + envVarKey: RENDER_EXTERNAL_URL + - key: NEXT_PUBLIC_MARKETING_URL + value: 'http://localhost:3001' + + # SMTP + - key: NEXT_PRIVATE_SMTP_TRANSPORT + value: 'smtp-auth' + - key: NEXT_PRIVATE_SMTP_HOST + sync: false + - key: NEXT_PRIVATE_SMTP_PORT + sync: false + - key: NEXT_PRIVATE_SMTP_USERNAME + sync: false + - key: NEXT_PRIVATE_SMTP_PASSWORD + sync: false + - key: NEXT_PRIVATE_SMTP_FROM_NAME + sync: false + - key: NEXT_PRIVATE_SMTP_FROM_ADDRESS + sync: false + + # Stripe + - key: NEXT_PRIVATE_STRIPE_API_KEY + sync: false + - key: NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET + sync: false + - key: NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID + sync: false + - key: NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID + sync: false + + # Features + - key: NEXT_PUBLIC_POSTHOG_KEY + sync: false + - key: NEXT_PUBLIC_POSTHOG_HOST + value: 'https://eu.posthog.com' + - key: NEXT_PUBLIC_FEATURE_BILLING_ENABLED + sync: false + + # Redis (Only required for marketing site, but added for completeness) + - key: NEXT_PRIVATE_REDIS_URL + sync: false + - key: NEXT_PRIVATE_REDIS_TOKEN + sync: false + + # Storage + - key: NEXT_PUBLIC_UPLOAD_TRANSPORT + value: 'database' + - key: NEXT_PRIVATE_UPLOAD_ENDPOINT + sync: false + - key: NEXT_PRIVATE_UPLOAD_REGION + sync: false + - key: NEXT_PRIVATE_UPLOAD_BUCKET + sync: false + - key: NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID + sync: false + - key: NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY + sync: false + +databases: + - name: documenso-db + plan: free