Open-source fashion e-commerce project built with a Rust API and a TypeScript admin frontend.
Silk is currently split into two applications:
service/- Rust backend API built with Axum, SQLx, PostgreSQL, Redis, Apalis workers, JWT authentication, and Handlebars email templates.admin/- React admin frontend built with TanStack Start, TanStack Router, TanStack Query, Vite, Tailwind CSS, Base UI, and shadcn-compatible UI tooling.
Local infrastructure is defined in compose.yaml and includes PostgreSQL,
Redis, and Mailtutan for catching development emails.
- Rust toolchain with Cargo
- Node.js and pnpm
- Docker or another Compose-compatible runtime
- PostgreSQL client tools are optional, but useful for inspecting the database
Create a root .env file for Docker Compose. The development configuration
expects these values:
POSTGRES_USER=usernamePOSTGRES_PASSWORD=passwordPOSTGRES_DB=databaseThese defaults match service/config/development.yaml. If you use different
database values, update that file or override the service setting when it is
started, for example with
APP_DATABASE_URI=postgresql://username:password@localhost:5432/database.
Start the local dependencies:
docker compose up -dRun the backend API:
cd service
cargo runThe service listens on http://127.0.0.1:7150 in development.
To load the bundled development users, roles, permissions, categories, and
product catalogue, run cargo run -- seed instead. Seeding happens during
startup and the API continues running afterward.
Run the admin frontend in a second terminal:
cd admin
pnpm install
pnpm devVite will print the local admin URL when the dev server starts.
The admin app calls the backend through VITE_SERVER_URL. If it is not set,
the client defaults to http://127.0.0.1:7150/api.
The backend loads configuration from service/config/<environment>.yaml.
Development is the default environment. You can choose another environment with
the --env flag:
cd service
cargo run -- --env testingConfiguration values can also be overridden with APP_-prefixed environment
variables. For example, APP_SERVER_PORT=8080 overrides server.port.
Useful commands:
cd service
cargo run # start the API
cargo run -- seed # seed all bundled data, then start the API
cargo test# run backend tests
cargo fmt # format Rust code
cargo clippy # run Rust lintsDevelopment JWT keys are configured under service/secrets/keys/dev/. Test
keys are configured under service/secrets/keys/test/.
All backend routes are mounted under /api. The service currently provides:
- Health and authentication endpoints, including registration, verification, cookie-based login, refresh-token rotation, logout, password recovery, and profile management.
- Public category and product reads with pagination and filtering.
- Permission-protected category and product creation, updates, soft deletion, variants, default variants, product pictures, and variant pictures.
- Authenticated role and permission reads, role management, role-permission assignment, and permission-protected user listing.
See service/README.md for the complete route
table, authentication rules, and supported catalogue filters.
Mailtutan exposes the local email inbox at http://localhost:1080; SMTP is
available on localhost:1025.
Useful commands:
cd admin
pnpm install # install dependencies
pnpm dev # start the Vite dev server
pnpm build # build for production
pnpm preview # preview the production build
pnpm test# run Vitest
pnpm lint # run oxlint
pnpm fmt:check # check formatting with oxfmt
pnpm fmt # format with oxfmt
pnpm generate-routes # regenerate TanStack Router route treeThe admin app supports these environment variables:
VITE_SERVER_URL- optional browser API base URLVITE_CLOUDINARY_*variables are no longer required. The service signs Cloudinary uploads server-side usingAPP_CLOUDINARY_CLOUD_NAME,APP_CLOUDINARY_API_KEY, andAPP_CLOUDINARY_API_SECRET.SERVER_URLandVITE_APP_TITLE- optional typed values that are not currently consumed by the app
The admin includes protected, API-backed screens for categories, products, customers, staff, roles, permissions, and account settings. Product management covers catalogue filtering, creation, detail, editing, variants, and pictures. The shared API client retries eligible requests after refreshing an expired session and redirects to sign-in when authentication cannot be restored.
.
|-- admin/ # TanStack Start admin frontend
| |-- src/api/ # Frontend API client functions and shared errors
| |-- src/components/ # App and UI components
| |-- src/routes/ # TanStack Router file routes
|-- service/ # Axum backend API
| |-- config/ # Environment-specific YAML config
| |-- migrations/ # SQLx database migrations
| |-- secrets/keys/ # Development and testing JWT keys
| |-- src/ # Application source
| |-- templates/ # Email templates
| `-- tests/ # Integration and model tests
|-- compose.yaml # PostgreSQL, Redis, and Mailtutan services
`-- README.md
- Database migrations run automatically when
database.auto_migrateis enabled in the selected service config. - The testing config uses port
7175and can recreate the database schema when tests start. - Redis is used by Apalis-backed mail workers and by auth refresh-token storage so refresh tokens are single-use and can be revoked on logout.
- Auth cookies are issued by the backend. Browser requests that need cookies should use credentials-enabled requests from the frontend.
- Admin image uploads go directly to Cloudinary when the two Cloudinary client environment variables are configured; the resulting URL is sent to the API.
admin/src/routeTree.gen.tsis generated by TanStack Router and should be regenerated withpnpm generate-routesafter route changes.