diff --git a/apps/docs/content/features/pricing.mdx b/apps/docs/content/features/pricing.mdx new file mode 100644 index 00000000..0661c575 --- /dev/null +++ b/apps/docs/content/features/pricing.mdx @@ -0,0 +1,177 @@ +--- +title: Pricing Plans & Usage +description: Detailed pricing description for deployment on zerops. +--- + +import PricingCalculator from "@site/src/components/PricingCalculator" +import { CheckCircleSolid } from "@medusajs/icons"; + +:::tip Calculate Your Costs +Use our basic [pricing calculator](#pricing-calculator) below to estimate your monthly costs based on your specific needs. +::: + +Zerops offers a usage based pricing model which can accommodate any **small-scale** or **high-availability** applications. The total price of hosting a application is equal to the project's **core package cost** + the **cost of the resources** of the services inside a project **(+ extra costs if any)**. + +## Project Plans + +Every deployment on Zerops requires a project, which provides essential infrastructure and functionality. Projects are the foundation of your application, handling core services like load balancing, routing, and container orchestration. + +### Lightweight Plan +- **Cost:** Free +- **Best for:** Development, testing, and small-scale applications +- **Infrastructure:** Single container setup +- **Limitations:** Shared IPv4 address, no high availability + +### Serious Plan +- **Cost:** $10 / 30 days +- **Best for:** Production and high-availability applications +- **Infrastructure:** Multi-container, highly available setup +- **Benefits:** Ready for production workloads with automatic failover + +:::info Billing +Project costs are calculated based on actual usage. You're only charged for the time your project is active, calculated down to the minute. +::: + +### Plan Comparison + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeaturesLightweight (Free)Serious ($10/30d)
Core ServicesSingle containerHighly available
HTTP Routing & Load BalancerSingle containerHighly available
Proxy / Load Balancer
IPv6 Address
Build Time15 hours150 hours
Backup Space5 GB25 GB
Egress100 GB3 TB
+ +### Additional Costs + +The following costs apply when you exceed the plan limits of a project: + + + + + + + + + + + + + + + + + + + + + + +
ResourceCost
Backup Space$0.50 per 5 GB
Build Time$0.50 per 15 hours
Egress Traffic$0.10 per 1 GB
+ + +## Service Resources + +Resources are allocated per service and billed by the minute, though credit is deducted hourly based on actual usage. + +### Resource Pricing + + + + + + + + + + + + + + + + + + + + + + + + + + +
ResourceCost
Shared CPU$0.60 per CPU / 30 days
Dedicated CPU$6.00 per CPU / 30 days
RAM$0.75 per 0.25 GB / 30 days
Disk space$0.05 per 0.5 GB / 30 days
+ +### Additional Features + + + + + + + + + + + + + + + + + + +
FeatureCost
Unique IPv4 address$3.00 / 30 days
Object Storage$0.01 / GB per 30 days
+ +:::info IPv4 and Cloudflare +By default, projects start with a shared IPv4 address. If you plan to use Cloudflare's proxy features, you'll need to purchase a unique IPv4 address for your project. +::: + +:::info Object Storage +External storage solution ideal for storing files, backups, and static assets outside your main storage. Perfect for scalable content delivery and backup strategies. +::: + +## Pricing Calculator + + + diff --git a/apps/docs/sidebars.js b/apps/docs/sidebars.js index 6a64e907..db321e9a 100644 --- a/apps/docs/sidebars.js +++ b/apps/docs/sidebars.js @@ -88,6 +88,15 @@ module.exports = { }, className: 'homepage-sidebar-item', }, + { + type: 'doc', + id: 'features/pricing', + label: 'Pricing Plans & Usage', + customProps: { + sidebar_icon: 'currency-dollar', + }, + className: 'homepage-sidebar-item', + }, // { // type: 'doc', // id: 'features/remote-dev', diff --git a/apps/docs/src/components/PricingCalculator/calculator.css b/apps/docs/src/components/PricingCalculator/calculator.css new file mode 100644 index 00000000..bd1f5f83 --- /dev/null +++ b/apps/docs/src/components/PricingCalculator/calculator.css @@ -0,0 +1,86 @@ +.calculator { + border: 1px solid #e2e8f0; +} + +.calculator-select { + appearance: none; + background-color: #ffffff; + border: 1px solid #e2e8f0; + border-radius: 0.5rem; + padding: 0.5rem 2rem 0.5rem 1rem; + width: 100%; + font-size: 1rem; + line-height: 1.5; + background-image: url("data:image/svg+xml,..."); + /* Add dropdown arrow icon */ + background-repeat: no-repeat; + background-position: right 0.75rem center; + background-size: 1rem; +} + +.calculator-select:focus { + outline: none; + border-color: #3182ce; + box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.1); +} + + +.number-input { + /* Remove spinner arrows for all browsers */ + -moz-appearance: textfield; + /* Firefox */ + appearance: textfield; +} + +.number-input::-webkit-outer-spin-button, +.number-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Rest of input styling */ +.number-input { + width: 100%; + padding: 0.5rem 1rem; + border: 1px solid #e2e8f0; + border-radius: 0.5rem; + font-size: 1rem; + line-height: 1.5; + background-color: #ffffff; +} + +.number-input:focus { + outline: none; + border-color: #3182ce; + box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.1); +} + +input[type="checkbox"] { + width: 1.5rem; + height: 1.5rem; + border: 1px solid #e2e8f0; + border-radius: 0.5rem; + background-color: #ffffff; + cursor: pointer; +} + +input[type="checkbox"]:checked { + background-color: #3182ce; + border-color: #3182ce; + padding: 0.25rem; + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); + background-size: 1.25rem; +} + +input[type="checkbox"]:focus { + outline: none; + border-color: #3182ce; + box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.1); +} + +.calculator-label { + padding-bottom: 1rem; + display: block; + font-weight: 500; + color: #4A5568; +} \ No newline at end of file diff --git a/apps/docs/src/components/PricingCalculator/index.tsx b/apps/docs/src/components/PricingCalculator/index.tsx new file mode 100644 index 00000000..5c2f5010 --- /dev/null +++ b/apps/docs/src/components/PricingCalculator/index.tsx @@ -0,0 +1,306 @@ +import React from 'react'; +import { Button, InputText } from 'docs-ui'; +import './calculator.css'; + +type ResourcesType = { + cpu: number; + cpuType: 'shared' | 'dedicated'; + ram: number; + disk: number; + storage: number; + ipv4_addr: boolean; + core: 'lightweight' | 'serious'; +}; + +export default function PricingCalculator() { + const [resources, setResources] = React.useState({ + cpu: 1, + cpuType: 'shared', + ram: 0.25, + disk: 0.5, + storage: 0, + ipv4_addr: false, + core: 'lightweight', + }); + + const price = { + cpu: resources.cpuType === 'shared' ? 0.6 : 6, + ram: 3, + disk: 0.05, + storage: 0.01, + ipv4_addr: 3, + core: resources.core === 'lightweight' ? 0.0 : 10.0, + }; + + const handleAdjust = (name: string, amount: number) => { + setResources((prev) => { + const currentValue = Number(prev[name as keyof typeof prev]); + const newValue = Number((currentValue + amount).toFixed(2)); + const minValue = name === 'cpu' ? 1 : 0; + return { + ...prev, + [name]: Math.max(minValue, newValue), + }; + }); + }; + + const handleChange = (name: string, value: number | string | boolean) => { + setResources((prev) => ({ + ...prev, + [name]: value, + })); + }; + + const calculateTotal = () => { + const total = + resources.cpu * price.cpu + + resources.ram * price.ram + + resources.disk * price.disk + + resources.storage * price.storage + + (resources.ipv4_addr ? price.ipv4_addr : 0) + + price.core; + + return total.toFixed(2); + }; + + const isMinValue = (name: string, value: number) => { + const minValues = { + cpu: 1, + ram: 0.25, + disk: 0.5, + storage: 0, + }; + return value <= minValues[name as keyof typeof minValues]; + }; + + return ( +
+
+
+ +
+ + { + const value = e.target.value; + if (value >= 0) { + setResources((prev) => ({ + ...prev, + cpu: value, + })); + } + }} + min="1" + step="1" + /> + +
+
+
+ + +
+
+ +
+ + { + const value = e.target.value; + if (value >= 0) { + setResources((prev) => ({ + ...prev, + ram: value, + })); + } + }} + min="0.25" + step="0.25" + /> + +
+
+
+ +
+ + { + const value = e.target.value; + if (value >= 0) { + setResources((prev) => ({ + ...prev, + disk: value, + })); + } + }} + min="0.5" + step="0.5" + /> + +
+
+
+ +
+ + { + const value = e.target.value; + if (value >= 0) { + setResources((prev) => ({ + ...prev, + storage: value, + })); + } + }} + min="0" + step="1" + /> + +
+
+ +
+ + +
+
+ +
+
+
+ Total price: ${calculateTotal()} / 30 + days +
+
+ ); +}