Repositories, local setup, configuration reference and the safety nets around MiStorage.
dotnet test from the repo root.xUnitperf/PERFORMANCE-REPORT.md.Frontend repodotnet tool install --global dotnet-ef.mistorage-backend project directory, set at least the connection string and JWT key with dotnet user-secrets set — the project already carries a UserSecretsId.dotnet ef database update applies the migrations and seeds roles, permissions and default settings. No admin user is seeded — register the first system user through the API or the frontend.dotnet run serves http://localhost:5179; dotnet run --launch-profile https adds https://localhost:7206. In Development the Scalar reference is at /scalar/v1.cd mistorage-backend
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Host=localhost;Database=mistorage;Username=postgres;Password=<yours>"
dotnet user-secrets set "Jwt:SecretKey" "<at least 32 bytes of randomness>"
dotnet user-secrets list
dotnet ef database update
dotnet rundotnet ef resolves its connection through the normal configuration chain, so in Development it uses the user-secrets value — your local Postgres. The connection string in appsettings.json is production. Never migrate production with database update; follow the deploy procedure in docs/deploy/README.md.
Every secret is empty in the tracked files on purpose. Supply them from user-secrets in development and from environment variables or a secret store in production. A blank value is never a usable default.
| Setting | Environment variable | Behaviour when missing |
|---|---|---|
ConnectionStrings:DefaultConnection | ConnectionStrings__DefaultConnection | Fails fast at startup |
Jwt:SecretKey (≥ 32 bytes) | Jwt__SecretKey | Fails fast at startup |
Email:Username / Email:Password | Email__Username / Email__Password | SMTP send fails at runtime |
PhoenixGate:MerchantPassword | PhoenixGate__MerchantPassword | Fails fast while PhoenixGate:Enabled is true |
PhoenixGate:QuickPaymentsKey | PhoenixGate__QuickPaymentsKey | Fails fast while PhoenixGate:Enabled is true |
PhoenixGate:ResellerPassword | PhoenixGate__ResellerPassword | Error on merchant boarding only |
Security:FieldEncryptionKey (32 bytes, base64 or hex) | Security__FieldEncryptionKey | Registrations carrying a Social Security Number are refused; everything else keeps working. Never falls back to plaintext. |
Security:TrustedProxySecret | Security__TrustedProxySecret | Optional. Unset, the API ignores the relay's X-Client-Ip and every relayed renter login shares one rate-limit bucket. |
| Setting | Default | What it does |
|---|---|---|
Saas:Enabled | false | false is the single-operator product. true restores the multi-tenant SaaS model whole. Mirror it in the frontend's NEXT_PUBLIC_SAAS_ENABLED. |
RenterAuth:RequireEmailVerification | true | On: a renter must confirm their email before the account works. Off: registration creates the account already verified and signs the renter in. Currently off in the tracked files while email delivery is blocked. |
PhoenixGate:Enabled | false | Whether cards are charged at all. Off, renting still completes and the first invoice is left outstanding for the location to collect. |
Email:Transport | Smtp | Mock writes outgoing mail to Email:MockDropPath instead of sending — used while SMTP is unavailable. |
Security:FieldEncryptionKey encrypts the renter's Social Security Number and nothing else. Losing it makes every stored SSN permanently unreadable, by design. Generate it with python -c "import os,base64;print(base64.b64encode(os.urandom(32)).decode())" and back it up wherever the other production secrets live.
dotnet ef migrations add <Name> # create a migration from model changes
dotnet ef database update # apply pending migrations (LOCAL only)
dotnet ef migrations remove # undo the last (unapplied) migration
dotnet ef migrations list # what is applied, what is pendingASPNETCORE_ENVIRONMENT=Development dotnet ef migrations script --idempotent \
--project mistorage-backend --output docs/deploy/migrate-idempotent-<yyyyMMdd>.sql
grep -nE "DROP COLUMN|DROP TABLE|RENAME|ALTER COLUMN|DROP CONSTRAINT|NOT NULL" <script>WHERE "Col" = TIMESTAMPTZ '0001-01-01' matched nothing on Postgres, because Npgsql renders DateTime.MinValue as -infinity.42703: column does not exist — that took the HQ dashboard down for four days in September.NOT NULL added to an existing table needs a DEFAULT; narrowing a column fails on any row already longer./api/*-auth/ relay routes handle POST only.** Route a GET or PUT through them and you get 405 in production and success in development.ExecuteDelete, no real SQL semantics, no constraint enforcement. Anything involving raw SQL, deletes or types needs a real database to be believed.tsc, eslint and next build are the whole safety net; changes to auth or checkout are verified by driving a real browser against a real backend.dotnet ef builds before it does anything. Stop the API before migrations add, database update or migrations script.