The setup API handles the initial configuration of a fresh Nanahoshi instance, creating the first admin user and organization.
Complete setup
Initialize a new Nanahoshi instance by creating the first admin user and workspace.
const result = await orpc.setup.complete.mutate({
workspaceName: "My Library",
workspaceSlug: "my-library",
username: "admin",
email: "[email protected]",
password: "securepassword123"
});
Parameters
Display name for the initial organization/workspace
URL-friendly slug for the organization (alphanumeric and hyphens only)
Username for the admin account
Email address for the admin account (must be valid email format)
Password for the admin account (minimum 8 characters)
Response
Whether the setup completed successfully
Setup flow
The setup process performs the following actions:
- Validates setup state - Ensures the app hasn’t already been configured
- Creates admin user - Registers the user via better-auth with the provided credentials
- Creates organization - Creates the initial workspace/organization
- Assigns owner role - Makes the user the organization owner
- Grants admin privileges - Sets the user’s global role to “admin”
- Marks as configured - Persists the setup completion state in the database
Setup guard
The setup endpoint is a public procedure (no authentication required) but can only be called once. After successful completion, all subsequent calls will return a FORBIDDEN error.
// First call - succeeds
await orpc.setup.complete.mutate({ /* ... */ });
// Second call - fails
await orpc.setup.complete.mutate({ /* ... */ });
// Error: Application is already configured
UI implementation
Example setup wizard component:
import { useState } from 'react';
import { orpc } from '@/utils/orpc';
import { useNavigate } from '@tanstack/react-router';
function SetupWizard() {
const navigate = useNavigate();
const [formData, setFormData] = useState({
workspaceName: '',
workspaceSlug: '',
username: '',
email: '',
password: ''
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await orpc.setup.complete.mutate(formData);
// Redirect to login after successful setup
navigate({ to: '/login' });
} catch (error) {
console.error('Setup failed:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<h1>Welcome to Nanahoshi</h1>
<p>Set up your digital library</p>
<input
placeholder="Workspace Name"
value={formData.workspaceName}
onChange={(e) => setFormData({
...formData,
workspaceName: e.target.value
})}
required
/>
<input
placeholder="Workspace Slug"
value={formData.workspaceSlug}
onChange={(e) => setFormData({
...formData,
workspaceSlug: e.target.value
})}
required
/>
<input
placeholder="Username"
value={formData.username}
onChange={(e) => setFormData({
...formData,
username: e.target.value
})}
required
/>
<input
type="email"
placeholder="Email"
value={formData.email}
onChange={(e) => setFormData({
...formData,
email: e.target.value
})}
required
/>
<input
type="password"
placeholder="Password (min 8 characters)"
value={formData.password}
onChange={(e) => setFormData({
...formData,
password: e.target.value
})}
required
minLength={8}
/>
<button type="submit">Complete Setup</button>
</form>
);
}
Setup detection
To determine if setup is required, you can check the app configuration status:
// This is typically done server-side in a route guard
import { isAppConfigured } from '@nanahoshi-v2/api/modules/settings.service';
const needsSetup = !(await isAppConfigured());
if (needsSetup) {
// Redirect to /setup
} else {
// Normal login flow
}
The first user created during setup receives admin privileges with full system access. Ensure you use a strong password and keep these credentials secure.
After setup completion, users should be directed to the login page. The initial admin can then sign in and configure libraries, invite other users, and set up organizations.